101. 对称二叉树
如果一个树的左子树与右子树镜像对称,那么这个树是对称的。
- 它们的两个根结点具有相同的值
- 每个树的 右子树 都与另一个树的 左子树 镜像对称
递归结束条件:
- 都为空指针则返回 True
- 只有一个为空或两个指针当前节点值是不相等则返回 False
递归过程:
- 判断 A 的右子树与 B 的左子树是否对称
- 判断 A 的左子树与 B 的右子树是否对称
方法一:递归
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
def check(p, q):
if not (p or q): return True
if not p or not q or p.val != q.val: return False
#if not (p and q and p.val == q.val): return False
return check(p.left, q.right) and check(p.right, q.left)
return check(root, root)
广度遍历
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
def helper(node, level):
if not node:
res[level-1].append(None)
return
else:
res[level-1].append(node.val)
if len(res) == level: # 遍历到新层时,只有最左边的结点使得等式成立
res.append([])
helper(node.left, level+1)
helper(node.right, level+1)
res = [[]]
helper(root, 1)
for i in res[:-1]:
if i != i[::-1]:return False
return True
方法二:迭代
初始化队列时把根节点入队两次。每次提取两个连续的结点进行比较,然后将两个结点的左右子结点按相反的顺序插入队列中。当队列为空时,或者检测到树不对称时,结束。
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
q = deque([root, root])
while q:
u = q.popleft()
v = q.popleft()
if not u and not v: continue
if not u or not v or u.val != v.val:
return False
q.extend([u.left, v.right])
q.extend([u.right, v.left])
return True
广度遍历
class Solution:
def isSymmetric(self, root: TreeNode) -> bool:
queue = [root]
while queue:
temp = []
layer = []
while queue:
cur = queue.pop()
if cur:
layer.append(cur.val)
temp.append(cur.left)
temp.append(cur.right)
else:
layer.append(None)
if layer != layer[::-1]:return False
queue = temp
return True
104. 二叉树的最大深度
方法一:深度优先搜索 DFS
class Solution:
def maxDepth(self, root: TreeNode) -> int:
return max(self.maxDepth(root.left),self.maxDepth(root.right)) + 1 if root else 0
方法二:广度优先搜索 BFS
存放一层,处理一层。
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root:return 0
res, q = 0, [root]
while q:
res += 1
temp = []
while q:
cur = q.pop()
if cur.left: temp.append(cur.left)
if cur.right: temp.append(cur.right)
q = temp
return res
class Solution:
def maxDepth(self, root: TreeNode) -> int:
if not root: return 0
res = 0
que = collections.deque([(root, 1)])
while que:
node, depth = que.popleft()
res = max(res, depth)
if node.left:
que.append((node.left, depth + 1))
if node.right:
que.append((node.right, depth + 1))
return res
111. 二叉树的最小深度
方法一:深度优先搜索
class Solution:
def minDepth(self, root: TreeNode) -> int:
if not root: return 0
if not root.left and not root.right: return 1
min_depth = 10**9
if root.left:
min_depth = min(self.minDepth(root.left), min_depth)
if root.right:
min_depth = min(self.minDepth(root.right), min_depth)
return min_depth + 1
方法二:广度优先搜索
class Solution:
def minDepth(self, root: TreeNode) -> int:
if not root:return 0
res, q = 0, [root]
while q:
res += 1
temp = []
while q:
cur = q.pop()
if cur.left: temp.append(cur.left)
if cur.right: temp.append(cur.right)
if not cur.left and not cur.right:return res
q = temp
return res
class Solution:
def minDepth(self, root: TreeNode) -> int:
if not root: return 0
que = collections.deque([(root, 1)])
while que:
node, depth = que.popleft()
if not node.left and not node.right:
return depth
if node.left:
que.append((node.left, depth + 1))
if node.right:
que.append((node.right, depth + 1))
return 0
112. 路径总和
根结点到叶子结点的路径上值的和 :在叶子结点上判断。
方法一:递归 DFS
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:return False
if not root.left and not root.right: # 叶子结点
return root.val == targetSum
# 问题转化为左右子树递归
return self.hasPathSum(root.right, targetSum - root.val) or self.hasPathSum(root.left, targetSum - root.val)
方法二:广度优先搜索 BFS
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root: return False
q = deque([(root, root.val)]) # 通过元组携带值
while q:
cur, tem = q.popleft()
if not cur.left and not cur.right: # 叶子结点
if tem == targetSum: return True
continue
cur.left and q.append((cur.left, cur.left.val + tem))
cur.right and q.append((cur.right, cur.right.val + tem))
return False
112. 路径总和
根结点到叶子结点的路径上值的和 :在叶子结点上判断。
方法一:递归 DFS
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:return False
if not root.left and not root.right: # 叶子结点
return root.val == targetSum
# 问题转化为左右子树递归
return self.hasPathSum(root.right, targetSum - root.val) or self.hasPathSum(root.left, targetSum - root.val)
方法二:广度优先搜索 BFS
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root: return False
q = deque([(root, root.val)]) # 通过元组携带值
while q:
cur, tem = q.popleft()
if not cur.left and not cur.right: # 叶子结点
if tem == targetSum: return True
continue
cur.left and q.append((cur.left, cur.left.val + tem))
cur.right and q.append((cur.right, cur.right.val + tem))
return False
113. 路径总和 II
方法一:DFS
cclass Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
def dfs(cur, tem):
path.append(cur.val)
tem -= cur.val
if not (cur.left or cur.right or tem):
res.append(path[:]) # copy
cur.left and dfs(cur.left, tem)
cur.right and dfs(cur.right, tem)
path.pop() # 回溯
if not root:return []
res , path = [], []
dfs(root, targetSum)
return res
方法二:广度优先搜索
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
if not root: return []
res = []
q = deque([(root, [], targetSum)]) # 结点,路径,路径和
while q:
cur, path, tem = q.popleft()
# path += [cur.val]
# path.append(cur.val) # 列表 +=,append 对象不变 !!!
path = path + [cur.val] # 对象变了
tem -= cur.val
# 如果是叶子节点,同时和为零。
if not cur.left and not cur.right and not tem:
res.append(path) # 保存路径
cur.left and q.append((cur.left, path, tem))
cur.right and q.append((cur.right, path, tem))
return res
114. 二叉树展开为链表
118. 杨辉三角
class Solution:
def generate(self, numRows: int) -> List[List[int]]:
res = []
for i in range(numRows):
tmp = [1] * (i+1)
for j in range(1,i):
tmp[j] = res[-1][j-1]+res[-1][j]
res.append(tmp)
return res
119. 杨辉三角 II
class Solution:
def getRow(self, rowIndex: int) -> List[int]:
res = []
for i in range(rowIndex+1):
tmp = [1] * (i+1)
for j in range(1,i):
tmp[j] = res[j-1] + res[j]
res = tmp
return res
使用一个数组,从上向下遍历,从右向左刷新;从前往后或从后往前,res[j] 都会被覆盖,从后往前用的是 res[j-1]。
class Solution:
def getRow(self, rowIndex: int) -> List[int]:
res = [1] * (rowIndex + 1) # 元素个数为 rowIndex + 1
for i in range(rowIndex + 1):
# i-1 跳过最后一个,0 跳过第一个 。
for j in range(i-1, 0, -1):
res[j] += res[j - 1]
return res