【力扣hot100】刷题笔记Day14

前言

  • 又是新的一周,快乐的周一,快乐地刷题,今天把链表搞完再干活!

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   

 后言

  • 搞定二叉树咯,头好晕啊,肯定是天气冻的,晚上再简单干点活就可以玩耍咯

  • 30
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值