代码随想录算法训练营 Day20|654.最大二叉树, 617.合并二叉树, 700.二叉搜索树中的搜索, 98.验证二叉搜索树

本文介绍了最大二叉树的构建方法,通过前序遍历策略找到最大值并递归分割数组。随后讨论了合并两个二叉树和在二叉搜索树中搜索的解决方案,强调了终止条件和递归返回值的重要性。最后,针对验证二叉搜索树的题目,解析了中序遍历的单调性检查方法。
摘要由CSDN通过智能技术生成

Day20|654.最大二叉树, 617.合并二叉树, 700.二叉搜索树中的搜索, 98.验证二叉搜索树

654.最大二叉树

思路

前序遍历
流程与前两题相似
根据最大值所在的index,切割数组,得到的左数组和右数组分别递归

尝试写代码

class Solution:
    def constructMaximumBinaryTree(self, nums: List[int]) -> Optional[TreeNode]:

        if not nums:
            return None
        
        root_val = max(nums)
        root = TreeNode(root_val)

        index = nums.index(root_val)
        left = nums[:index]
        right = nums[index + 1:]
        
        root.left = self.constructMaximumBinaryTree(left)
        root.right = self.constructMaximumBinaryTree(right)

        return root

成功通过!

617.合并二叉树

思路

终止条件:如果两个二叉树都是叶子节点,则返回None

尝试写代码

class Solution:
    def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:

        if not root1.left and not root1.right and not root2.left and not root2.right:
            return None

        if not root1.left and root2.left:
            return root2.left
        if not root2.left and root1.left:
            return root1.left
        if not root1.right and root2.right:
            return root2.right
        if not root2.right and root1.right:
            return root1.right

        if root1 and root2:
            root_val = root1.val + root2.val
            root = TreeNode(root_val)
        
        root.left = self.mergeTrees(root1.left, root2.left)
        root.right = self.mergeTrees(root1.right, root2.right)

        return root

结果不对

根据代码随想录视频
要点:

  1. 使用前序,最容易理解
  2. 确定参数和返回值,参数为传入的两个树,返回值就是返回的树的根节点
  3. 终止条件:如果tree1为空,返回tree2;如果tree2为空,返回tree1;如果都为空,返回None,不需要额外写,已经包含在前两个条件里了。
  4. 如何处理返回值:如果tree1为空,要返回tree2的该节点,即此时要返回以该节点为根节点的整个子树,需要将该节点返回给上一层。
  5. 不需要重新创建二叉树,直接更改tree1就好

最终代码:

class Solution:
    def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
        if not root1:
            return root2
        if not root2:
            return root1
        
        root = TreeNode(0)
        root.val = root1.val + root2.val
        root.left = self.mergeTrees(root1.left, root2.left)
        root.right = self.mergeTrees(root1.right, root2.right)

        return root

总结
处理当前节点,考虑的比较简单,就不用分左右了。终止条件中,处理的方式,简单有效,是我一开始想复杂了。
根据视频的思路,写出来非常简单!

700.二叉搜索树中的搜索

思路

写终止条件时,不确定如果找到了节点值等于val的节点 这一条件是否应该算作终止条件,还是算中的处理逻辑。
如果算终止条件,那返回值应该是root,而如果遍历到叶子节点,返回None。
这样在左右递归时,需要判断,如果有返回值,则继续向上返回,最后返回None。

尝试写代码:

class Solution:
    def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
        if not root:
            return None
        if root.val == val:
            return root
        
        left = self.searchBST(root.left, val)
        if left:
            return left 
        right = self.searchBST(root.right, val)
        if right:
            return right

        return None

成功通过!
但是有点不明白,为什么最后返回None,而不是空列表。
debug之后,确实是返回None;题目要求也是返回None,只不过例子给出的返回了[]。注意审题!

根据代码随想录,本题是一个二叉搜索树,上面自己写的代码思路适用于普通二叉树,应该根据二叉搜索树的特性写。

要点:

  1. 二叉搜索树自带顺序,不需要考虑递归的顺序
  2. 终止条件有两个,一个是节点为空,另一个是满足条件。写的时候可以写成都返回root的形式。
  3. 给定值比节点小,搜索左子树;比节点值大,搜索右子树。
  4. 注意递归函数有返回值,需要定义一个临时变量,用来接住返回值。

最终代码:

class Solution:
    def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]:
        if not root or root.val == val:
            return root

        result = TreeNode(None)
        if val < root.val:
            result = self.searchBST(root.left, val)
        if val > root.val:
            result = self.searchBST(root.right, val)
        
        return result

98.验证二叉搜索树

思路

如何判断整个右子树大于当前节点?
如果只分析当前节点,那就有可能只有右节点满足,而右节点的左节点可能比当前值小。
那就需要右子树的全部节点与当前节点比较,这样时间复杂度很高
不知道有没有什么简单有效的算法。

尝试用后序遍历写代码:

class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        if not root.left and not root.right:
            return True

        if root.left:
            if not self.isValidBST(root.left):
                return False
        if root.right:
            if not self.isValidBST(root.right):
                return False
        
        if root.left and root.right and root.left.val < root.val and root.right.val > root.val:
            return True
        else:
            return False

测试用例正确,但结果不对。
感觉终止条件设的不对,该思路也没有解决一开始想到的问题。

根据代码随想录:
要点:

  1. 中序遍历二叉搜索树,元素单调递增
  2. 定义一个pre节点,在中的处理逻辑中,比较当前节点和前一节点的值,不满足则返回True
  3. 终止条件,考虑极端情况,返回True

最终代码:

class Solution:
    def __init__(self):
        self.prev = None

    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        if not root:
            return True

        left = self.isValidBST(root.left)
        if self.prev and self.prev.val >= root.val:
            return False
        self.prev = root
        right = self.isValidBST(root.right)
        return left and right

注意:
只需要定义类内全局变量时,创建init函数

解法二:中序遍历后的数组,判断其是不是单调递增

class Solution:
    def isValidBST(self, root: Optional[TreeNode]) -> bool:
        self.result = []
        self.is_asc(root)
        for i in range(1, len(self.result)):
            if self.result[i - 1] >= self.result[i]:
                return False
        return True

    def is_asc(self, root):
        if not root:
            return
        self.is_asc(root.left)
        self.result.append(root.val)
        self.is_asc(root.right)
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值