二叉树专题
230. 二叉搜索树中第K小的元素(🎂)
class Solution:
def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
# 二叉搜索树中序遍历的结果是一个递增序列,所以使用dfs,直接中序遍历k次即可
self.ans = 0
self.cnt = 0
def dfs(root):
if not root: return
dfs(root.left)
self.cnt += 1
if k == self.cnt:
self.ans = root.val
return
dfs(root.right)
dfs(root)
return self.ans
108. 将有序数组转换为二叉搜索树(🎂)
class Solution:
def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
# 每次选nums的中位数来作为根节点
# n = len(nums)
# root = TreeNode(nums[n // 2])
def dfs(nums):
if not nums: return None
if len(nums) == 1:
return TreeNode(nums[0])
n = len(nums)
node = TreeNode(nums[n // 2])
node.left = dfs(nums[:n // 2])
node.right = dfs(nums[n // 2 + 1:])
return node
return dfs(nums)
109. 有序链表转换二叉搜索树(🎂)
笨方法是先吧链表转化成有序数组,之后就是108题一模一样了。但是这么做肯定不是最优解,但是时间复杂度应该是很低了。
class Solution:
def sortedListToBST(self, head: Optional[ListNode]) -> Optional[TreeNode]:
# 最笨的方法,先将链表转化成数组
nums = []
while head:
nums.append(head.val)
head = head.next
# 之后按照有序数组转二叉搜索树的方法转就可以了
def dfs(nums):
if not nums: return
if len(nums) == 1: return TreeNode(nums[0])
n = len(nums)
node = TreeNode(nums[n // 2])
node.left = dfs(nums[:n // 2])
node.right = dfs(nums[n // 2 + 1:])
return node
return dfs(nums)
110. 平衡二叉树
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def isBalanced(self, root: Optional[TreeNode]) -> bool:
if not root: return True
return abs(self.height(root.left) - self.height(root.right)) <= 1 and self.isBalanced(root.left) and self.isBalanced(root.right)
def height(self, root):
if not root: return 0
return max(self.height(root.left), self.height(root.right)) + 1
111. 二叉树的最小深度
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if not root: return 0
def recur(root):
if not root: return float('inf')
if not root.left and not root.right: return 1
return min(recur(root.left), recur(root.right)) + 1
return recur(root)
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
if not root: return 0
if not root.left and not root.right: return 1
# 如果一个节点缺失了左子节点或者右子节点,那么不会递归进入缺失子树
min_depth = 10**9 + 1 # 给最小深度初始化一个很大的数
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
112. 路径总和
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root:
return False
def dfs(root, target):
if not root: return False
if not root.left and not root.right and target == root.val: return True
left = dfs(root.left, target - root.val)
right = dfs(root.right, target - root.val)
return left or right
return dfs(root, targetSum)
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root: return False
if not root.left and not root.right and targetSum == root.val: return True
return self.hasPathSum(root.left, targetSum - root.val) or self.hasPathSum(root.right, targetSum - root.val)
113. 路径总和 II
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
paths, path = [], []
def dfs(root, target):
if not root: return
path.append(root.val)
target = target - root.val
if not root.left and not root.right and target == 0:
paths.append(path[:])
# 为啥那么这里不直接return呢?按道理说应该有一个return,但是加上去之后结果不对了
# return
dfs(root.left, target)
dfs(root.right, target)
# target += root.val
path.pop() # 虽然上面递归了两次,但是只需要pop一次
dfs(root, targetSum)
return paths
上面的代码其实不是很好理解,因为安扎去哦正常的回溯,满足条件之后可以直接return
,但是官方解答中上面的代码为了优雅一些可能,多走了下面连个dfs两次,所以造成了很多人误解。
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
paths, path = [], []
def dfs(root, target):
if not root: return
if not root.left and not root.right and target == root.val:
paths.append(path[:] + [root.val])
return
path.append(root.val)
target -= root.val
dfs(root.left, target)
dfs(root.right, target)
# target += root.val # 加不加这一句不影响
path.pop()
dfs(root, targetSum)
return paths
116. 填充每个节点的下一个右侧节点指针
class Solution:
def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
if not root: return root
stack = [root]
while stack:
n = len(stack)
for i in range(n):
node = stack.pop(0)
if i < n - 1:
node.next = stack[0]
if node.left: stack.append(node.left)
if node.right: stack.append(node.right)
return root
117. 填充每个节点的下一个右侧节点指针 II
class Solution:
def connect(self, root: 'Node') -> 'Node':
if not root: return root
stack = [root]
while stack:
n = len(stack)
for i in range(n):
node = stack.pop(0)
if i < n - 1:
node.next = stack[0]
if node.left: stack.append(node.left)
if node.right: stack.append(node.right)
return root
BFS版本上面两道题代码一模一样
235. 二叉搜索树的最近公共祖先(🎂)
要充分利用二叉搜索树的特性。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
# 二叉搜索树的好处是可以根据p,q以及当前节点的值来判断在左右子树中搜索p还是q
if not root: return
# 当前节点就是最近的祖先
if root.val == p.val or root.val == q.val: return root
# 分散在两边
if p.val < root.val < q.val: return root
if q.val < root.val < p.val: return root
# 聚集在一边
if max(p.val, q.val) < root.val:
return self.lowestCommonAncestor(root.left, p, q)
elif max(p.val, q.val) > root.val:
return self.lowestCommonAncestor(root.right, p, q)
236. 二叉树的最近公共祖先(🎂)
这个就完全没有任何的规律,只有不断地试。
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root: return
# 当前节点就是最近的祖先
if root.val == p.val or root.val == q.val: return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if left and right: return root # 分散在两边
# 这里不能使用这种判断是因为,return root左右都为空的时候,还是会返回root,这个时候应该返回None。所以最后改成return 就可以了
# if left: return left # 聚集在左边
# if right: return right # 聚集在右边
if not left: return right # 左边没有,那就是右边
if not right: return left # 右边没有,那就是左边
return root # 左右都没有,那就是找不到
class Solution:
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if not root: return root
# 当前节点就是最近的祖先
if root.val == p.val or root.val == q.val: return root
left = self.lowestCommonAncestor(root.left, p, q)
right = self.lowestCommonAncestor(root.right, p, q)
if left and right: return root # 分散在两边
return left if left else right
剑指 Offer II 054. 所有大于等于节点的值之和(🎂)
要使用逆向的中序遍历
class Solution:
def convertBST(self, root: TreeNode) -> TreeNode:
# 因为要找比该节点大的所有节点,所以应该使用逆序的中序遍历
self.sum = 0
def inorder(root):
if not root: return 0
inorder(root.right)
root.val = root.val + self.sum
self.sum = root.val
inorder(root.left)
return
inorder(root)
return root