算法训练 Day 23

LeetCode 669. 修剪二叉搜索树

题目链接:669. 修剪二叉搜索树

思路:与删除二叉树节点的思路有些相似,不过较之更复杂一些。当出现当前节点数值小于low时,应该遍历右孩子(以便之后将右子树接上),不好理解的话可以看看LC官方提供的示例2,0节点不符合要求移除之后,是其右孩子接上的;当出现当前节点数大于high时,同理,应该遍历左子树。

做这种题的时候,如果过程实在有些抽象一开始没思路的话,可以看看题目提供的示例,看个例子能好很多。

Python版本:

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

时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( n ) O(n) O(n)

go版本:

func trimBST(root *TreeNode, low int, high int) *TreeNode {
    if root == nil {
        return root
    }
    if root.Val < low {
        right := trimBST(root.Right, low, high)
        return right
    }
    if root.Val > high {
        left := trimBST(root.Left, low, high)
        return left
    }
    root.Left = trimBST(root.Left, low, high)
    root.Right = trimBST(root.Right, low, high)
    return root
}

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

题目链接:108. 将有序数组转换为二叉搜索树

思路:题目要求转换为一棵高度平衡的二叉搜索树,不然的话直接每次往右孩子上添加一个就行了(那也没有做的必要了,而且实际生活中那种树也极其不方便),既然要高度平衡的话,那细想一下,我们应该找到最中间的那个值来当根节点。

这里又引申出来两个新的问题,如果当前遍历的数组是偶数个呢,那最中间的两个数值,我们选哪个来当根节点都是可以的,只是最后构造的二叉树结构会不一样罢了。
第二个问题就是,递归到下一层的时候,数组的范围应该怎么确定。一般这种二分问题,都是左闭右开或者左闭右闭,这道题使用左闭右闭的逻辑会好理解一些:首先把根节点确定下来,那根节点左侧的区间就是左子树,右侧的区间就是右子树。

Python版本:

class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        def foo(nums, left, right):
            if left > right:
                return
            mid = left + (right-left+1)//2
            root = TreeNode(nums[mid])
            root.left = foo(nums, left, mid-1)
            root.right = foo(nums, mid+1, right)
            return root
        return foo(nums, 0, len(nums)-1)

时间复杂度: O ( N ) O(N) O(N),空间复杂度: O ( l o g 2 N ) O(log_2 {N}) O(log2N)

go版本:

func sortedArrayToBST(nums []int) *TreeNode {
    return foo(nums, 0, len(nums)-1)
}

func foo(nums []int, left int, right int) *TreeNode {
    if left>right {
        return nil
    }
    mid := left + (right-left+1)/2
    root := &TreeNode{}
    root.Val = nums[mid]
    root.Left = foo(nums, left, mid-1)
    root.Right = foo(nums, mid+1, right)
    return root
}

LeetCode 538. 把二叉搜索树转换为累加树

题目链接:538. 把二叉搜索树转换为累加树

思路:在我的Day 21的算法训练中,多次使用了pre指针的方法:在遍历二叉树的时候记录上一个节点,此题又用到了,pre指针是好用的,之后做动态规划的题的时候滚动数组的变量设置有着异曲同工之妙。

此题还有一个重要的细节,就是该怎么遍历二叉树才能实现题目的要求。我们掌握的二叉树的遍历顺序有三种:前序、中序、后序遍历。但模拟了一下,发现这三种遍历方式都无法满足题目的要求,我们再细读一下题目,模拟一下思路。题目要求使每个节点node的新值等于原树中大于或等于 node.val的值之和,又因为给我们的是一个二叉搜索树,所以大于node.val的值的节点全部在node的右侧。
先从最简单的一步想一下,这样说的话,整棵二叉树应该是最右端的叶子节点还是原来的值(因为它最大),之后它的父节点只需要加上它即可(也就是整棵树中第二大的),…,依次类推,我们可以逐渐发现,我们遍历再相加的二叉树节点的顺序是右子树-根节点-左子树,实际上就是中序遍历正好反过来了。

Python版本:

class Solution:
    def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
        def foo(root):
            nonlocal pre
            if root:
                foo(root.right)
                root.val += pre
                pre = root.val
                foo(root.left)
        
        pre = 0
        foo(root)
        return root

时间复杂度: O ( n ) O(n) O(n),空间复杂度: O ( n ) O(n) O(n)

go版本:


var pre int

func convertBST(root *TreeNode) *TreeNode {
    pre = 0
    return foo(root)
}

func foo(root *TreeNode) *TreeNode {
    if root==nil {
        return nil
    }
    foo(root.Right)
    root.Val += pre
    pre = root.Val
    foo(root.Left)
    return root
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值