LeetCode HOT100刷题笔记(七):二叉树

【如果笔记对你有帮助,欢迎关注&点赞&收藏,收到正反馈会加快更新!谢谢支持!】

ps:笔记和代码按本人理解整理,重思路

题目43:验证二叉搜索树

98. 验证二叉搜索树 - 力扣(LeetCode)

  • 题意:判断其是否是一个有效的二叉搜索树
  • 关键:
    • 二叉搜索树特性 “左子树所有节点 < 当前节点 < 右子树所有节点”
    • 二叉搜索树的中序遍历得到的结果是有序(递增)【只要满足这个条件就是二叉搜索树】
  • 拆解:
    「代码逻辑」
    
    pre:前一个节点值
    验证二叉搜索树(root)
    	如果root为None:True
    	1. 验证二叉搜索树(左子树) -> True/False
    	2. 【处理中间节点】
    		当前节点和pre比较:-> True/False
    		pre <- 当前节点
    	3. 验证二叉搜索树(右子树) -> True/False
    	注:1 & 2 & 3 都为True才可以(如果1为False,2也不用进行)
    	
  •  代码:
    class Solution:
        pre = -inf
        def isValidBST(self, root: Optional[TreeNode]) -> bool:
            if not root:
                return True
            # 不满足条件的情况,直接返回False;先遍历left(按照中序遍历顺序)
            if not self.isValidBST(root.left) or root.val <= self.pre:
                return False
            self.pre = root.val # 更新self.pre
            return self.isValidBST(root.right)

题目44: 二叉搜索树中第 K 小的元素

230. 二叉搜索树中第 K 小的元素 - 力扣(LeetCode)

  • 关键:和题目43同理,利用二叉搜索树中序遍历的有序性
  • 代码:
    class Solution:
        def kthSmallest(self, root: Optional[TreeNode], k: int) -> int:
            count = 0
            result = None
    
            def dfs(root):
                if not root:
                    return 
                    
                dfs(root.left)
    
                nonlocal count, result
                count += 1
                if count == k:
                    result = root.val
    
                dfs(root.right)
    
            dfs(root)
            return result
    

题目45:二叉树的右视图

199. 二叉树的右视图 - 力扣(LeetCode)

  • 题意:找到二叉树每层最右边的节点
  • 直接方法:同 题目41:二叉树的层序遍历
  • 递归方法:先遍历左子树再遍历右子树  → 同样深度后遍历(右)的覆盖先遍历(左)
    class Solution:
        def rightSideView(self, root: Optional[TreeNode]) -> List[int]:
            result = []
            def dfs(root, height):
                if not root: return 
     
                if height >= len(result):  # 第一次遇到当前深度
                    result.append(root.val)
                else:         # 覆盖同样深度左侧的节点
                    result[height] = root.val
     
                dfs(root.left, height+1)
                dfs(root.right, height+1)
     
            dfs(root, 0)
            return result

题目46:二叉树展开为链表

114. 二叉树展开为链表 - 力扣(LeetCode)

  • 题意:将二叉树展成链表(并到右侧),按“先序遍历”排序
  • 关键:用栈stack以“先右后左”的顺序存节点  → 取出时“先左后右”
  • 代码:
    class Solution:
        def flatten(self, root: Optional[TreeNode]) -> None:
            """
            Do not return anything, modify root in-place instead.
            """
            if not root:
                return None
            stack = [root]
            prev = None
            while stack:
                node = stack.pop()
                if node.right:
                    stack.append(node.right)
                if node.left:
                    stack.append(node.left)
                
                if prev:
                    prev.right = node
                    prev.left = None
                
                prev = node
            
            return root

题目47:从前序与中序遍历序列构造二叉树

105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)

  • 题意:用二叉树的前序遍历和中序遍历,构造二叉树
  • 关键:root = 前序遍历第一个,左子树 = 中序遍历的root左侧,右子树 = 中序遍历的root右侧
  • 代码:
    class Solution:
        def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
            if not preorder:
                return None
            left_size = inorder.index(preorder[0])
            left = self.buildTree(preorder[1: 1+left_size], inorder[:left_size])
            right = self.buildTree(preorder[1+left_size:], inorder[1+left_size:])
            return TreeNode(preorder[0], left, right)

题目48:路径总和 III

437. 路径总和 III - 力扣(LeetCode)

  • 题意:找到满足目标和的二叉树的路径(自上而下的任意一段)
  • 关键:哈希表记录前缀和
  • 拆解:
    「代码逻辑」
    # 自上而下传递
    prefix:哈希表记录前缀和 {前缀和:数量}
    路径总和(root, 之前的路径和):
    	- 更新路径和 = 之前的路径和 + 当前值
    	- 更新结果:+(新路径和-前缀和==target)的数量
    	- 更新哈希表:{新路径和: 数量+1}
    	- 路径总和(root.left, 新路径和)
    	- 路径总和(root.right, 新路径和)
  • 代码:
    class Solution:
        def pathSum(self, root: Optional[TreeNode], targetSum: int) -> int:
            ans = 0
            prefix = defaultdict(int)
            prefix[0] = 1
            
            def dfs(root, s):
                if not root:
                    return 
                nonlocal ans
                s += root.val
                ans += prefix[s - targetSum]
                prefix[s] += 1
                dfs(root.left, s)
                dfs(root.right, s)
                prefix[s] -= 1
            
            dfs(root, 0)
            return ans

题目49: 二叉树的最近公共祖先

236. 二叉树的最近公共祖先 - 力扣(LeetCode)

  • 最近公共祖先:对于有根树 T 的两个节点 p、q,最近公共祖先表示为一个节点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先
  • 关键:自下而上传递
  • 代码:
    class Solution:
        def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
            if root is None or root is p or root is q:
                return root
            left = self.lowestCommonAncestor(root.left, p, q)
            right = self.lowestCommonAncestor(root.right, p, q)
            if left and right:
                return root
            elif left:
                return left
            elif right:
                return right

     

题目50: 二叉树中的最大路径和

124. 二叉树中的最大路径和 - 力扣(LeetCode)

  • 题意:找到二叉树中和最大的路径(不限制方向)
  • 关键:动态规划;自下而上传递
    • 总路径 = top1长的子节点路径【左边的深度】 → 当前节点 → top2长的子节点路径【右边的深度】
    • 因为路径和可为负,所以最大值不一定是整段路径
  • 拆解:
    「代码逻辑」
    # 自下而上传递
    
    找最大路径和(root):
    	- 左路径 = 找最大路径和(root.left)
    	- 右路径 = 找最大路径和(root.right)
    	- 更新结果 max(1.左中右 2.左中 3.右中 4.中)
    	- return max(左中,右中,中)#需要自下而上一个方向的路径

  • 代码:
    class Solution:
        def maxPathSum(self, root: Optional[TreeNode]) -> int:
            result = float('-inf')
            def searchPath(root):
                if not root:
                    return 0
                left = searchPath(root.left)
                right = searchPath(root.right)
                nonlocal result
                result = max(result, left+root.val+right, left+root.val, root.val+right, root.val)
                return max(left, right, 0) + root.val
            
            searchPath(root)
            return result

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值