【LeetCode Hot100】二叉树复习(Python版)

递归三部曲

1. 参数和返回值:寻找某一条边(或者一个节点)的时候,递归函数会有bool类型的返回值,找到不符合的节点立刻返回,如果符合则遍历了整棵树

2. 终止条件:一般为空节点

3. 单层递归逻辑:遍历顺序

代码模板

  • 前/中/后序遍历 递归法模板
  • 前/中/后序遍历 迭代法模板
  • 层次遍历 模板

经典错题

1. 验证二叉搜索树

二叉搜索树的定义:根节点的左子树节点的值都小于根节点的值,根节点的右子树节点的值都大于根节点的值

递归三部曲:

(1)参数:节点;返回值:bool类型一旦不符合直接返回

(2)终止条件:因为需要都小于和都大于,因此用一个遍历记录节点的值,一旦出现根节点的值大于后续节点,返回False,否则更新节点值

(3)单层递归逻辑:中序遍历(二叉搜索树是有序的),左右递归,中间处理

2. 二叉树展开为链表

解题思路:记录右子树,将左子树移到右子树的位置,再将右子树放在左子树的最右端

递归三部曲:

(1)参数:节点;返回值:空(需要遍历整棵树)

(2)终止条件:空节点

(3)单层递归逻辑:记录右子树,递归左子树,递归右子树(找到最下面的节点),将左子树移到右子树,然后将原来的右子树移到最右端

class Solution:
    def flatten(self, root: Optional[TreeNode]) -> None:
        """
        Do not return anything, modify root in-place instead.
        """
        #递归
        #参数:节点;返回值:空
        #终止条件:空
        #单层递归逻辑:右子树插入到左子树最右端,左子树插入到右子树
        if not root: return 
        right=root.right #记录右子树
        self.flatten(root.left) #递归左子树
        self.flatten(root.right) #递归右子树
        root.left,root.right=None,root.left #最下面的左子树插入到右子树
        node=root #记录根节点
        while node.right:
            node=node.right #记录根节点的右子树
        node.right=right #将原来右子树插入到左子树的最右边

3. 从前序与中序遍历序列构造二叉树

解题思路:前序序列的第一个数为根节点,找到在中序序列的位置,划分为左右两个子树,找到左右两个子树的元素在前序序列的范围,递归上述过程

第一步:前序序列的第一个元素作为根节点

第二步:找到在中序序列的位置

第三步:分为左中序序列和右中序序列

第四步:分为左前序序列和右前序序列

第五步:递归左中序序列和左前序序列;递归右中序序列和右前序序列

第六步:返回根节点

class Solution:
    def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
        if not preorder: return 
        #第一步,用前序序列第一个节点构造根节点
        root=TreeNode(preorder[0])
        #第二步,找到在中序序列的位置
        mid=inorder.index(preorder[0])
        #第三步,划分左右两个序列
        left_inorder=inorder[:mid]
        right_inorder=inorder[mid+1:]
        #第四步,划分前序序列
        left_preorder=preorder[1:len(left_inorder)+1]
        right_preorder=preorder[len(left_inorder)+1:]
        #第五步,递归
        root.left=self.buildTree(left_preorder,left_inorder)
        root.right=self.buildTree(right_preorder,right_inorder)
        return root

4. 路径总和Ⅲ

递归三部曲:

(1)参数:节点、目标值;返回值:方案数

(2)终止条件:当搜索到节点为空,返回0个方案

(3)单层递归逻辑:节点非空,判断当前节点值是否等于目标值,若是,方案数+1

否则,目标值更新为targetsum-root.val,递归左子树,递归右子树,将返回的方案数累加

**注意,首先从根节点出发,其次考虑根节点的左孩子和右孩子出发

代码:

class Solution:
    def pathSum(self, root: TreeNode, targetSum: int) -> int:
        def rootSum(root, targetSum):
            if root is None: #终止条件:节点为空,返回方案数为0
                return 0

            ret = 0
            if root.val == targetSum: #如果节点非空,且节点值等于目标值,则方案数+1
                ret += 1

            ret += rootSum(root.left, targetSum - root.val) #递归左子树
            ret += rootSum(root.right, targetSum - root.val) #递归右子树
            return ret
        
        if root is None:
            return 0
            
        ret = rootSum(root, targetSum)
        ret += self.pathSum(root.left, targetSum)
        ret += self.pathSum(root.right, targetSum)
        return ret

5. 二叉树的最近公共祖先

解题思路:如果p和q位于根节点的两侧,返回根节点,如果p和q位于同一侧,则返回离根节点最近的节点

递归三部曲:

(1)参数:root,p,q;返回值:bool类型

(2)终止条件:当root==p或root==q或root为空时,返回节点本身

(3)单层递归逻辑:后序遍历,左(递归左子树)右(递归右子树)中(如果左右非空返回根节点;如果左空右非空,返回右;如果左非空右空,返回左)

代码:

class Solution:
    def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
        #参数:root,p,q;返回值:返回bool(节点)
        #终止条件:遇到p/q立即返回,遇到空节点,返回节点本身
        #单层递归逻辑:后序遍历,返回值的处理
        if root == q or root == p or root is None:
            return root

        left = self.lowestCommonAncestor(root.left, p, q)
        right = self.lowestCommonAncestor(root.right, p, q)

        if left is not None and right is not None:
            return root

        if left is None and right is not None:
            return right
        elif left is not None and right is None:
            return left
        else: 
            return None

6. 二叉树中的最大路径和

解题思路:题目说明路径可以经过根节点,可以不经过根节点,选取那个路径和,主要看哪个更大,因此需要使用一个全局变量保存较大值(初始化为无穷小);在选择值的时候,保存非负数

递归三部曲:

(1)参数:节点;返回值:路径和

(2)终止条件:当节点为空,路径为0

(3)单层递归逻辑:后序遍历

left=左子树的路径和(递归左子树)

right=右子树的路径和(递归右子树)

中间节点的处理mid=left+right+root.val (经过中间节点的路径)

使用全局变量选取较大值,即max_sum = max(mid,max_sum)

返回值:单边路径和 root.val+max(left,right)

代码:

class Solution:
    def __init__(self):
        self.max_sum=float('-inf')

    def maxPathSum(self, root: Optional[TreeNode]) -> int:
        def traversal(root):
            if not root:
                return 0
            #选择非负的
            left=max(traversal(root.left),0) #单边值
            right=max(traversal(root.right),0)
            mid=root.val+left+right #经过中间节点
            self.max_sum=max(mid,self.max_sum) #全局变量记录较大值

            return root.val+max(left,right)#可以不经过中间节点
        traversal(root)
        return self.max_sum

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值