代码随想录算法训练营第二十一天| 二叉树8— 669. 修剪二叉搜索树,108. 将有序数组转换为二叉搜索树

二叉树章节最后一天,三道题都和修改树的结构或者节点值有关。669. 修剪二叉搜索树108. 将有序数组转换为二叉搜索树538. 把二叉搜索树转换为累加树。觉得还是有难度,重点是感觉自己有关改变树结构,比如增删节点之类的题目掌握的还不好。

 669. 修剪二叉搜索树

669. 修剪二叉搜索树 - 力扣(LeetCode)

感觉进入修改树结构的题之后,迭代法的难度就变高了很多,虽然整体思路和递归差不多,但是判断条件复杂度变高了很多。原本习惯一开始拿队列或者栈去思考迭代遍历然后再转换为递归方法,但是现在迭代复杂了很多,很难从迭代开始想起,反而是先从递归入手了(总结来说还是太菜了)。

这道题的递归其实很简单,参数就是root和上下限,停止条件是root为none, 单层递归中判断是否越界,即小于最小值或者大于最大值,如果有,利用二叉搜索树的特性往另一边走,后续正常递归就行。注意一下赋值的是root.left这种,这是为了将树连接起来,之前有时候只是为了作比较操作,只返回left/right等就行了,这是更改树结构题相关题目一个变化的点,其余递归过程变化不大。

迭代法确实麻烦了很多。但是思路还是简单,先找到符合条件的根节点,找到之后再去分别修改左右子树。主要是自己代码基础还是不行,还有就是二叉搜索树这个条件利用不好,熟练应用左节点<根节点<右节点这个性质会方便很多。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    # 递归
    def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
        if not root:
            return None

        if root.val < low:
            return self.trimBST(root.right, low, high)
        if root.val > high:
            return self.trimBST(root.left, low, high)
        
        root.left = self.trimBST(root.left, low, high)
        root.right = self.trimBST(root.right, low, high)

        return root
    
    # 迭代
    def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]:
        if not root:
            return None

        while root and (root.val < low or root.val > high): # 找符合条件的根节点
            if root.val > low:
                root = root.left
            elif root.val < high:
                root = root.right
        cur = root
        while cur: # 剪左子树
            while cur.left and cur.left.val < low:
                cur.left = cur.left.right
            cur = cur.left

        cur = root
        while cur: # 剪右子树
            while cur.right and cur.right.val > high:
                cur.right = cur.right.left
            cur = cur.right

        return root
        

108. 将有序数组转换为二叉搜索树

108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)

读完题就想到了106. 从中序与后序遍历序列构造二叉树这一系列的题目,都是利用一个数组去构造二叉树的。这道题思路也很明显,利用二叉搜索树性质,从数组中间开始作为根节点,然后分别去做左边区间的中间值和右边区间的中间值最后逐步构造出二叉搜索树。

递归法依旧是比较简单好想一点。一共三个参数,数组,以及左右边界。但停止条件变了,因为这次不再是遍历到空节点,而是构造二叉树,所以当left>right就停止,因为这就证明了区间不存在了。单层递归内就是简单的二分查找,找出中间值并创建根节点,然后往左右递归左右区间。

迭代这个是真麻烦,真没想到需要用这么麻烦的方法做,需要同时维护三个队列,自己做的时候就一直在想怎么表达左右边界索引,没想到是直接多加两个队列,看来还是不够狠心。思路和递归大体上一样,需要注意每次迭代需要先构建一个节点TreeNode(0),才能开始逐步迭代,进行pop,后续把二分的值赋值回来覆盖掉就行。

# Definition for a binary tree node.
# class TreeNode:
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution:
    # 递归
    def create(self, nums, left, right):
        if left > right:
            return None
        
        mid = (left + right) // 2
        root = TreeNode(nums[mid])
        
        root.left = self.create(nums, left, mid - 1)
        root.right = self.create(nums, mid + 1, right)

        return root
    def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        return self.create(nums,0,len(nums)-1)

    # 迭代
    def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        if len(nums) == 0:
            return None
        
        root = TreeNode(0)
        q = deque()
        left = deque()
        right = deque()

        q.append(root)
        left.append(0)
        right.append(len(nums)-1)

        while q:
            node = q.popleft()
            left_index = left.popleft()
            right_index = right.popleft()

            mid = left_index + (right_index - left_index) // 2

            node.val = nums[mid]

            if left_index <= mid-1:
                node.left = TreeNode(0)
                q.append(node.left)
                left.append(left_index)
                right.append(mid - 1)

            if right_index >= mid+1:
                node.right = TreeNode(0)
                q.append(node.right)
                left.append(mid+1)
                right.append(right_index)
        return root
        

剩下一道累加树的题目比较常规,只是一直遍历的时候是左中右,但是发现递归的时候写右中左也行,还是要灵活一点。依旧是双指针做法,一个指针指向当前值,一个指针在后面把所有当前值累加,逐步更新就好。

最后是二叉树总结

代码随想录

补一个常见的终止条件返回情况,免得自己有时候乱return

return 0   用来计算 数值总和、计数、加法汇总

return None 用来处理 结构类型,比如返回某个子树、找某个节点

return [] 用来收集 路径、列表结果

return True/False 用在 判断型递归(比如是否存在路径、是否符合条件)

 

经历了最长的一个章节,大概刷了有三四十道左右的二叉树题目。目前感觉遍历有关的题目掌握的还不错,简单题和部分中等题都能有思路,代码框架也都能写出来,可能经常会有一些小错误,比如递归方向搞反,self忘记等,但是自己调试一下也能出来,再难一点的就不太行了,最起码也得看看题解有点思路才能大概写一下。更改树结构的题目掌握一般,有点困难,主要是很容易想复杂,递归思路也很乱,比如删除之后不知道怎么拼接后续子树,还得多练。后续有时间肯定要再回头复盘一下二叉树这块的题目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值