深度是指树的根节点到任一叶子节点路径上节点的数量。
最大深度是所有叶子节点的深度的最大值。
(注:叶子节点是指没有子节点的节点。)
数据范围:0 \le n \le 1000000≤n≤100000,树上每个节点的val满足 |val| \le 100∣val∣≤100
要求: 空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
class Solution:
def maxDepth(self , root: TreeNode) -> int:
if root is None:
return 0
if root.left is None and root.right is None:
return 1
leftdep = 1 + self.maxDepth(root.left)
rightdepth = 1 + self.maxDepth(root.right)
return max(leftdep, rightdepth)
在这里,我们只需要考虑其平衡性,不需要考虑其是不是排序二叉树
平衡二叉树(Balanced Binary Tree),具有以下性质:它是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。
样例解释:
class Solution:
"""
@param root: The root of binary tree.
@return: True if this Binary tree is Balanced, or false.
"""
res = True
def is_balanced(self, root: TreeNode) -> bool:
# write your code here
self.scan(root)
return self.res
def scan(self, node:TreeNode) -> int:
if self.res == False:
return 0
if node is None:
return 0
left = self.scan(node.left)
right = self.scan(node.right)
if abs(left - right) > 1:
self.res = False
return max(left, right) + 1
平衡二叉搜索树指树上每个节点 node 都满足左子树中所有节点的的值都小于 node 的值,右子树中所有节点的值都大于 node 的值,并且左右子树的节点数量之差不大于1
数据范围:0 \le n \le 100000≤n≤10000,数组中每个值满足 |val| \le 5000∣val∣≤5000
进阶:空间复杂度 O(n)O(n) ,时间复杂度 O(n)O(n)
class Solution:
def sortedArrayToBST(self , num: List[int]) -> TreeNode:
length = len(num)
if length == 0:
return None
if length == 1:
return TreeNode(num[0])
bleng = int(length / 2)
node = TreeNode(num[bleng])
node.left = self.sortedArrayToBST(num[:bleng])
node.right = self.sortedArrayToBST(num[bleng+1:])
return node
子树指一棵树的某个节点的全部后继节点
数据范围:树的节点数满足 0 < n \le 5000000
class Solution:
def isContains(self , root1: TreeNode, root2: TreeNode) -> bool:
curr = self.find_node(root1, root2)
return self.node_compare(curr, root2)
def find_node(self, node1: TreeNode, node2: TreeNode) -> TreeNode:
nodes = []
nodes.append(node1)
while len(nodes) > 0:
curr_node = nodes.pop(0)
if curr_node.val == node2.val:
return curr_node
if curr_node.left is not None:
nodes.append(curr_node.left)
if curr_node.right is not None:
nodes.append(curr_node.right)
return None
def node_compare(self, node1: TreeNode, node2: TreeNode) -> bool:
if (node1 is None and node2 is not None) or (node1 is not None and node2 is None):
return False
if node1 is None and node2 is None:
return True
if node1.val != node2.val:
return False
leftb = self.node_compare(node1.left, node2.left)
rightb = self.node_compare(node1.right, node2.right)
return leftb and rightb
1.该题的直径定义为:树上任意两个节点路径长度的最大值
2.该题路径长度定义为:不需要从根节点开始,也不需要在叶子节点结束,也不需要必须从父节点到子节点,一个节点到底另外一个节点走的边的数目
3.这个路径可能穿过根节点,也可能不穿过
4.树为空时,返回 0
如,输入{1,2,3,#,#,4,5},二叉树如下:
class Solution:
maxlength = 0
def diameterOfBinaryTree(self , root: TreeNode) -> int:
if root is None:
return 0
self.maxdeep(root)
return self.maxlength
def maxdeep(self, root) -> int:
if root is None:
return 0
left = self.maxdeep(root.left) + 1 if root.left is not None else 0
right = self.maxdeep(root.right) + 1 if root.right is not None else 0
self.maxlength = max(self.maxlength, left+right)
return max(left, right)
后序遍历是值按照 左节点->右节点->根节点 的顺序的遍历。
数据范围:二叉树的节点数量满足 1 \le n \le 100 \1≤n≤100 ,二叉树节点的值满足 1 \le val \le 100 \1≤val≤100 ,树的各节点的值各不相同
class Solution:
data = []
def postorderTraversal(self , root: TreeNode) -> List[int]:
self.scan(root)
return self.data
def scan(self, node:TreeNode):
if node is None:
return
if node.left is not None:
self.scan(node.left)
if node.right is not None:
self.scan(node.right)
self.data.append(node.val)
class Solution:
data = []
def preorderTraversal(self , root: TreeNode) -> List[int]:
self.scan(root)
return self.data
def scan(self, node:TreeNode):
if node is None:
return
self.data.append(node.val)
if node.left is not None:
self.scan(node.left)
if node.right is not None:
self.scan(node.right)
合并规则是:都存在的结点,就将结点值加起来,否则空的位置就由另一个树的结点来代替。例如:
class Solution:
def mergeTrees(self , t1: TreeNode, t2: TreeNode) -> TreeNode:
if t1 is None and t2 is None:
return None
if t1 is None and t2 is not None:
return t2
if t1 is not None and t2 is None:
return t1
t1.val += t2.val
t1.left = self.mergeTrees(t1.left, t2.left)
t1.right = self.mergeTrees(t1.right, t2.right)
return t1
1.对于该题的最近的公共祖先定义:对于有根树T的两个节点p、q,最近公共祖先LCA(T,p,q)表示一个节点x,满足x是p和q的祖先且x的深度尽可能大。在这里,一个节点也可以是它自己的祖先.
2.二叉搜索树是若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值; 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值
3.所有节点的值都是唯一的。
4.p、q 为不同节点且均存在于给定的二叉搜索树中。
数据范围:
3<=节点总数<=10000
0<=节点值<=10000
class Solution:
def lowestCommonAncestor(self , root: TreeNode, p: int, q: int) -> int:
# write code here
if p <= root.val and q >= root.val or p >= root.val and q <= root.val:
return root.val
if p <= root.val and q <= root.val:
return self.lowestCommonAncestor(root.left, p, q)
if p >= root.val and q >= root.val:
return self.lowestCommonAncestor(root.right, p, q)
1.修剪掉当前二叉树的叶子节点,但是不能直接删除叶子节点
2.只能修剪叶子节点的父节点,修剪了父节点之后,叶子节点也会对应删掉
3.如果想在留下尽可能多的节点前提下,修剪掉所有的叶子节点。请你返回修剪后的二叉树。
有如下二叉树:
class Solution:
def pruneLeaves(self , root):
if root is None:
return None
if self.check_leaf_node(root.left) or self.check_leaf_node(root.right):
return None
self.scan(root.left, root, "left")
self.scan(root.right, root, "right")
return root
def scan(self, node:TreeNode, parent:TreeNode, side: str):
if node is None:
return
if self.check_leaf_node(node.left) or self.check_leaf_node(node.right):
if parent is not None:
if side == "left":
parent.left = None
else:
parent.right = None
return
if node.left is not None:
self.scan(node.left, node, "left")
if node.right is not None:
self.scan(node.right, node, "right")
def check_leaf_node(self, node:TreeNode) -> bool:
if node is None:
return False
if node.left is None and node.right is None:
return True
return False
例如:
给定的二叉树是{3,9,20,#,#,15,7},
class Solution:
date = []
def levelOrder(self , root: TreeNode) -> List[List[int]]:
# write code here
if root is None:
return []
self.scan(root)
return self.date
def scan(self, root):
nodes = []
nodes.append(root)
while nodes:
res = []
length = len(nodes)
for i in range(length):
tmp = nodes.pop(0)
res.append(tmp.val)
if tmp.left is not None:
nodes.append(tmp.left)
if tmp.right is not None:
nodes.append(tmp.right)
self.date.append(res)
数据范围:0 \le n \le 15000≤n≤1500,树上每个节点的val满足 |val| <= 1500∣val∣<=1500
要求:空间复杂度:O(n)O(n),时间复杂度:O(n)O(n)
例如:
给定的二叉树是{1,2,3,#,#,4,5}
class Solution:
flag = 0
data = []
def Print(self , pRoot: TreeNode) -> List[List[int]]:
# write code here
if pRoot is None:
return self.data
nodes = []
nodes.append(pRoot)
while nodes:
length = len(nodes)
val = []
tempnode = []
for i in range(length):
tmp = nodes.pop(0)
if tmp.left is not None:
nodes.append(tmp.left)
if tmp.right is not None:
nodes.append(tmp.right)
tempnode.append(tmp)
for i in range(length):
tmp = tempnode.pop(self.flag)
val.append(tmp.val)
self.flag = -1 if self.flag == 0 else 0
self.data.append(val)
return self.data
数据范围:树上节点数满足 1 \le n \le 10^5 \1≤n≤10
5
, 节点值val满足区间 [0,n)
要求:时间复杂度 O(n)O(n)
注:本题保证二叉树中每个节点的val值均不相同。
class Solution:
def lowestCommonAncestor(self , root: TreeNode, o1: int, o2: int) -> int:
return self.scan(root, o1, o2).val
def scan(self, node:TreeNode, target1: int, target2:int) -> TreeNode:
if node is None:
return
if node.val == target1 or node.val == target2:
return node
l = self.scan(node.left, target1, target2)
r = self.scan(node.right, target1, target2)
if not l:
return r
if not r:
return l
return node
1.该题路径定义不需要从根节点开始,也不需要在叶子节点结束,但是一定是从父亲节点往下到孩子节点
2.总节点数目为n
3.保证最后返回的路径个数在整形范围内(即路径个数小于231-1)
class Solution:
total = 0
def FindPath(self , root: TreeNode, sum: int) -> int:
# write code here
if root is None:
return 0
self.scan(root, sum)
self.FindPath(root.left, sum)
self.FindPath(root.right, sum)
return self.total
def scan(self, node: TreeNode, sum: int):
if node is None:
return
if node.val == sum:
self.total += 1
if node.left is not None:
self.scan(node.left, sum - node.val)
if node.right is not None:
self.scan(node.right, sum - node.val)
二叉搜索树满足每个节点的左子树上的所有节点均小于当前节点且右子树上的所有节点均大于当前节点。
class Solution:
flag = True
def isValidBST(self , root: TreeNode) -> bool:
if root is None:
return True
if self.is_leaf(root):
return True
self.scan(root)
return self.flag
def scan(self, node:TreeNode) -> int:
if self.flag == False:
return node.val
if self.is_leaf(node):
return node.val
if node.left is not None and self.scan(node.left) > node.val:
self.flag = False
if node.right is not None:
r = self.scan(node.right)
if r < node.val:
self.flag = False
return r
return node.val
def is_leaf(self, node: TreeNode) -> bool:
if node is None:
return True
return node.left is None and node.right is None
完全二叉树的定义:若二叉树的深度为 h,除第 h 层外,其它各层的结点数都达到最大个数,第 h 层所有的叶子结点都连续集中在最左边,这就是完全二叉树。(第 h 层可能包含 [1~2h] 个节点)
hint: 解体思路就是广度优先去遍历, 如果前面出现None(不分哪一层), 后续没有出现None节点,则说明不是完全二叉树
class Solution:
flag = True
def isCompleteTree(self , root: TreeNode) -> bool:
if root is None:
return True
if root.left is None and root.right is None:
return True
self.scan(root)
return self.flag
def scan(self, node:TreeNode):
nodes = []
nodes.append(node)
pre_hasnone = False
while nodes:
length = len(nodes)
for i in range(length):
tmp = nodes.pop(0)
if tmp is None:
pre_hasnone = True
else:
if pre_hasnone:
self.flag = False
return
nodes.append(tmp.left)
nodes.append(tmp.right)
完全二叉树指:设二叉树的深度为h,则 [1,h-1] 层的节点数都满足 2^{i-1}2
i−1
个
数据范围:节点数量满足 0 \le n \le 1000000≤n≤100000,节点上每个值都满足 0 \le val \le 1000000≤val≤100000
进阶:空间复杂度 O(1)O(1) , 时间复杂度 O(n)O(n)
class Solution:
num = 0
def nodeNum(self , head: TreeNode) -> int:
if head is None:
return 0
if head.left is None and head.right is None:
return 1
self.scan(head)
return self.num
def scan(self, node:TreeNode) :
if node is None:
return 0
self.num += 1
if node.left is not None:
self.scan(node.left)
if node.right is not None:
self.scan(node.right)
数据范围:二叉树的节点数满足 1 \le n \le 1000 \1≤n≤1000 ,节点上的值满足 |val| \le 10^9 \∣val∣≤10
9
,保证节点的值各不相同
例如输入[2,1,4,3,5],[2,4,5,3,1]时,
根据中序遍历的结果[2,1,4,3,5]和后序遍历的结果[2,4,5,3,1]可构造出二叉树{1,2,3,#,#,4,5},如下图所示:
说明: 此类问题总结下:
1. 先生成root, 后然基于root值在另外一个数组的索引位置, 将两个数组分别拆分, 然后基于拆分的数组迭代
class Solution:
def buildTree(self , inorder: List[int], postorder: List[int]) -> TreeNode:
if not inorder or not postorder:
return None
curr_value = postorder[-1]
root = TreeNode(curr_value)
index = inorder.index(curr_value)
root.left = self.buildTree(inorder[:index], postorder[:index])
root.right = self.buildTree(inorder[index+1:], postorder[index:-1])
return root
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。
class Solution:
def reConstructBinaryTree(self , pre: List[int], vin: List[int]) -> TreeNode:
if not pre or not vin:
return None
root = TreeNode(pre[0])
index = vin.index(pre[0])
root.left = self.reConstructBinaryTree(pre[1:index+1], vin[:index])
root.right = self.reConstructBinaryTree(pre[index+1:], vin[index+1:])
return root
1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点
2.叶子节点是指没有子节点的节点
3.路径只能从父节点到子节点,不能从子节点到父节点
4.总节点数目为n
例如根节点到叶子节点的一条路径是1\to 2\to 31→2→3,那么这条路径就用\ 123 123 来代替。
找出根节点到叶子节点的所有路径表示的数字之和
class Solution:
def sumNumbers(self , root: TreeNode) -> int:
if root is None:
return 0
if root.left is None and root.right is None:
return root.val
return self.scan(root, 0)
def scan(self, node:TreeNode, total) -> int:
if node is None:
return 0
total = total * 10 + node.val
if node.left is None and node.right is None:
return total
return self.scan(node.left, total) + self.scan(node.right, total)
1.该题路径定义为从树的根结点开始往下一直到叶子结点所经过的结点
2.叶子节点是指没有子节点的节点
3.路径只能从父节点到子节点,不能从子节点到父节点
4.总节点数目为n
class Solution:
data = []
def FindPath(self , root: TreeNode, target: int) -> List[List[int]]:
if root is None:
return []
self.scan(root, target, [])
return self.data
def scan(self, node:TreeNode, target:int, path:[int]):
if node is None:
return
path = path + [node.val]
if node.left is None and node.right is None and node.val == target:
self.data.append(path)
return
if node.left is not None:
self.scan(node.left, target - node.val, path)
if node.right is not None:
self.scan(node.right, target - node.val, path)
return
输出描述:分别输出是否为搜索二叉树、完全二叉树。
数据范围:二叉树节点数满足 0 \le n \le 5000000≤n≤500000 ,二叉树上的值满足 0 \le val \le 10^60≤val≤10
6
要求:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)
注意:空子树我们认为同时符合搜索二叉树和完全二叉树。
class Solution:
is_search = True
is_tree = True
nodes = []
def judgeIt(self , root: TreeNode) -> List[bool]:
self.scan_search(root)
self.scan_tree(root)
return [self.is_search, self.is_tree]
def scan_tree(self, node: TreeNode):
if node is None:
return
nodes = []
nodes.append(node)
pre_has_node = False
while nodes:
length = len(nodes)
for i in range(length):
tmp = nodes.pop(0)
if tmp is None:
pre_has_node = True
continue
else:
print("4123", pre_has_node == True)
if pre_has_node == True:
self.is_tree = False
return
nodes.append(tmp.left)
nodes.append(tmp.right)
def scan_search(self, node:TreeNode) -> int:
if self.is_search == False :
return
if node is None:
return None
if node.left is None and node.right is None:
return node.val
lf = self.scan_search(node.left)
lr = self.scan_search(node.right)
value = None
if lf is not None:
if node.val < lf:
self.is_search = False
return
value = node.val
if lr is not None:
if node.val > lr:
self.is_search = False
return
value = lr
return value
例如:
给定的二叉树是{1,2,3,#,#,4,5}
class Solution:
data = []
def Print(self , pRoot: TreeNode) -> List[List[int]]:
# write code here
if pRoot is None:
return []
nodes = [pRoot]
while nodes:
length = len(nodes)
tmp = []
for i in range(length):
node = nodes.pop(0)
if node is not None:
tmp.append(node.val)
if node.left:
nodes.append(node.left)
if node.right:
nodes.append(node.right)
self.data.append(tmp)
return self.data
搜索二叉树:满足每个节点的左子节点小于当前节点,右子节点大于当前节点。
样例1图
# 这种解法 先输出有序的list, 然后在list中找到两个顺序错乱的数据, 空间复杂度O(n) 值得优化
class Solution:
data = []
def findError(self , root: TreeNode) -> List[int]:
# write code here
self.scan(root)
temp = []
is_first = True
length = len(self.data)
for i in range(length):
if i+1 < length and self.data[i] > self.data[i+1]:
if is_first:
temp.append(self.data[i])
temp.append(self.data[i+1])
is_first = False
else:
temp[1] = self.data[i+1]
return temp[::-1]
def scan(self, node:TreeNode) :
if node is None:
return
if node.left is None and node.right is None:
self.data.append(node.val)
return
if node.left:
self.scan(node.left)
self.data.append(node.val)
if node.right:
self.scan(node.right)
本题中树第 i 层的宽度定义为:第 i 层最左边的节点到最右边之间的距离,中间空节点也计入距离。
class Solution:
length = 0
def widthOfBinaryTree(self , root: TreeNode) -> int:
if root is None:
return 0
nodes = [root]
while nodes:
length = len(nodes)
start = None
has_value = False
for i in range(length):
node = nodes.pop(0)
if node is None :
nodes.append(None)
nodes.append(None)
continue
else:
has_value = True
if start is None:
start = i
self.length = max(self.length, 1)
else:
self.length = max(self.length, i - start + 1)
nodes.append(node.left)
nodes.append(node.right)
if has_value == False:
nodes = []
return self.length
数据范围:1 \le n \le 30001≤n≤3000
进阶:空间复杂度 O(1)O(1) , 时间复杂度 O(nlogn)O(nlogn)
# 一开始用的是递归, 后来数据大了就跑不动, 后面改成动态规划了
class Solution:
def numberOfTree(self, n: int) -> int:
dp = [0] * (n+1)
if n <= 1:
return 1
if n== 2:
return 2
dp[0] = 1
dp[1] = 1
dp[2] = 2
for i in range(3, n + 1):
for j in range(1, i+1):
dp[i] += dp[j-1] * dp[i - j]
dp[i] = dp[i] % 1000000007
return dp[n]
注意:
1.同一个节点在一条二叉树路径里中最多出现一次
2.一条路径至少包含一个节点,且不一定经过根节点
给定一个二叉树的根节点root,请你计算它的最大路径和
例如:
给出以下的二叉树,
最优路径是:2=>1=>3,或者3=>1=>2,最大路径和=2+1+3=6
数据范围:节点数满足 0 \le n \le 10^50≤n≤10
5
,节点上的值满足 |val| \le 1000∣val∣≤1000
要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)
// 跑了70的测试用例(怀疑测试用例有问题)
import sys
sys.setrecursionlimit(15000)
class Solution:
max_num = -1000
def maxPathSum(self , root: TreeNode) -> int:
self.scan(root)
return self.max_num
def scan(self, node:TreeNode) -> int:
if node is None:
return 0
self.max_num = max(self.max_num, node.val)
if node.left is None and node.right is None:
return node.val
lf = self.scan(node.left)
lr = self.scan(node.right)
value = max(lr, lf) + node.val
self.max_num = max(self.max_num, lr, lf, value, lr+lf+node.val)
return max(value, node.val)