前言
- 又是新的一周,快乐的周一,快乐地刷题,今天把链表搞完再干活!
114. 二叉树展开为链表 - 力扣(LeetCode)
-
前序递归:时间O(n),空间O(n)
-
class Solution: def flatten(self, root: Optional[TreeNode]) -> None: if not root: return self.flatten(root.left) # 展平左边 self.flatten(root.right) # 展平右边 right = root.right # 保存右子树 root.left, root.right = None, root.left # 左边断开,接到右边 node = root while node.right: node = node.right # 走到尾 node.right = right # 接回右子树
-
-
前序遍历:时间O(n),空间O(n)
-
class Solution: def flatten(self, root: Optional[TreeNode]) -> None: if not root: return st = [root] pre = None while st: cur = st.pop() # 把当前遍历结点接到上一个遍历结点上 if pre: pre.left = None pre.right = cur if cur.right: st.append(cur.right) if cur.left: st.append(cur.left) pre = cur return root
-
-
前驱结点:时间O(n),空间O(1)
-
class Solution: def flatten(self, root: Optional[TreeNode]) -> None: cur = root while cur: pre = cur if cur.left: cur = cur.left while cur.right: cur = cur.right # cur指向pre左子树的最右(前驱) cur.right = pre.right # pre右子树接在前驱上 pre.right = pre.left # pre左子树移到右子树 pre.left = None # pre左指针置为None cur = pre.right # cur继续往右 return root
105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)
-
递归:复制数组O(n2)
-
class Solution: def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: if not preorder: return None root = TreeNode(preorder[0]) # 构造根节点 idx = inorder.index(preorder[0]) # 找到根节点在中序中的idx,O(n) root.left = self.buildTree(preorder[1: idx+1], inorder[0: idx]) # 递归构造左子树 root.right = self.buildTree(preorder[idx+1:], inorder[idx+1:]) # 递归构造右子树 return root
-
-
递归:数组下标+哈希O(n)
-
-
-
class Solution: def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode: def dfs(i, l, r): if r - l < 0: return None # 子树区间为空时终止 root = TreeNode(preorder[i]) # 初始化根节点 m = inorder_map[preorder[i]] # 查询 m ,从而划分左右子树 root.left = dfs(i + 1, l, m - 1) # 子问题:构建左子树 root.right = dfs(i + 1 + m - l, m + 1, r) # 子问题:构建右子树 return root # 回溯返回根节点 # 初始化哈希表,存储 inorder 元素到索引的映射 inorder_map = {val: i for i, val in enumerate(inorder)} root = dfs(0, 0, len(inorder) - 1) return root
-
-
迭代
- 比较难理解和模拟,可以只记上面的递归方法即可,参考官解
-
class Solution: def buildTree(self, preorder: List[int], inorder: List[int]) -> TreeNode: if not preorder: return None root = TreeNode(preorder[0]) stack = [root] inorderIndex = 0 for i in range(1, len(preorder)): preorderVal = preorder[i] node = stack[-1] if node.val != inorder[inorderIndex]: node.left = TreeNode(preorderVal) stack.append(node.left) else: while stack and stack[-1].val == inorder[inorderIndex]: node = stack.pop() inorderIndex += 1 node.right = TreeNode(preorderVal) stack.append(node.right) return root
437. 路径总和 III - 力扣(LeetCode)
-
双重递归
- 两种方法思路参考题解,后者类似【力扣hot100】刷题笔记Day5-CSDN博客
-
class Solution: # 求包含与不包含root的所有路径中满足要求的路径数 def pathSum(self, root: TreeNode, sum: int) -> int: if not root: return 0 return self.dfs(root, sum) + self.pathSum(root.left, sum) + self.pathSum(root.right, sum) # 求包含root的所有路径中满足要求的路径数 def dfs(self, root, path): if not root: return 0 path -= root.val return (1 if path==0 else 0) + self.dfs(root.left, path) + self.dfs(root.right, path)
-
前缀和 + 哈希
-
class Solution: def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int: prefixSumTree = {0:1} # 前缀和:个数 self.count = 0 # 答案 prefixSum = 0 # 记录当前前缀和 self.dfs(root, sum, prefixSum, prefixSumTree) return self.count def dfs(self, root, targetSum, prefixSum, prefixSumTree): if not root: return 0 prefixSum += root.val oldSum = prefixSum - targetSum # 之前可能存在的等于目标和的路径和=当前前缀和-目标和 if oldSum in prefixSumTree: self.count += prefixSumTree[oldSum] # 存在的话结果加上路径数 prefixSumTree[prefixSum] = prefixSumTree.get(prefixSum, 0) + 1 # 如果不用collections.defaultdict,键不存在就返回默认值0,再+1 self.dfs(root.left, targetSum, prefixSum, prefixSumTree) self.dfs(root.right, targetSum, prefixSum, prefixSumTree) '''一定要注意在递归回到上一层的时候要把当前层的prefixSum的个数-1,类似回溯,要把条件重置''' prefixSumTree[prefixSum] -= 1
-
236. 二叉树的最近公共祖先 - 力扣(LeetCode)
-
递归后序
-
class Solution: def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': if not root or root == p or root == q: return root left = self.lowestCommonAncestor(root.left, p, q) right = self.lowestCommonAncestor(root.right, p, q) if left and right: return root # 找到祖先了 if not left: return right # 一边没有就返回另一边 if not right: return left
124. 二叉树中的最大路径和 - 力扣(LeetCode)
-
递归后序
-
class Solution: def maxPathSum(self, root: Optional[TreeNode]) -> int: self.maxSum = -float('inf') # 以防路径是负值 # 递归计算左右子节点的最大贡献值 def maxGain(node): if not node: return 0 leftGain = maxGain(node.left) # 左贡献 rightGain = maxGain(node.right) # 右贡献 newPath = leftGain + rightGain + node.val # 最大路径 = 左右贡献值+当前值 self.maxSum = max(self.maxSum, newPath) # 更新答案 return max(max(leftGain, rightGain) + node.val, 0) # 返回贡献值,为负数就不贡献了 maxGain(root) return self.maxSum
-
后言
- 搞定二叉树咯,头好晕啊,肯定是天气冻的,晚上再简单干点活就可以玩耍咯