669.修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树

669.修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树

669.修剪二叉搜索树

力扣题目链接(opens new window)

给定一个二叉搜索树,同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树,使得所有节点的值在[L, R]中 (R>=L) 。你可能需要改变树的根节点,所以结果应当返回修剪好的二叉搜索树的新的根节点。

669.修剪二叉搜索树

669.修剪二叉搜索树1

思路:递归法

遍历二叉树过程中,判断结点的值。如果在区间内,继续递归。如果不在区间内分成两种情况
第一种情况:当前结点val小于区间最小值。那结点的左子树不用考虑。结点的右子树可能存在符合条件的值,所以对结点的右子树处理,最后返回符合条件的右子树根节点
第二种情况:当前结点的val大于区间最大值。那结点的右子树不用考虑,结点的左子树可能存在符合条件的值,所以对结点的左子树处理,最后返回符合条件的左子树根结点
那么理解了核心逻辑,开始递归法三要素
1.方法入参和返回值: 入参 root根节点 low high 返回值 TreeNode
因为遍历的树是整个树,我们知道根节点root,没有返回值也可以。有返回值的目的是为了方便递归
2.中止条件
当遍历到空姐点时,结束递归
3.核心逻辑
如果当前结点root的值小于区间最小值,那么递归root右子树,返回符合条件的右子树根节点
if (root.val < low) {
return travel(root.right,low,high);
}
如果当前结点root的值大于区间最大值,那么递归root左子树,返回符合条件的左子树根节点
if (root.val > high) {
return travel(root.left,low,high);
}
接下来将下一层处理完结果赋值给root.left和root.right,并返回root
root.left = travel(root.left, low, high);
root.right = travel(root.right, low, high);
return root;

代码如下

// 时间复杂度o(n)
// 空间复杂度o(n)
public static TreeNode trimBST(TreeNode root, int low, int high) {
    return travel(root, low, high);
}

public static TreeNode travel(TreeNode root, int low, int high) {
    if (root == null)
        return null;


    if (root.val > high) {
        return travel(root.left,low,high);
    }
    if (root.val < low) {
        return travel(root.right,low,high);
    }

    root.left = travel(root.left, low, high);
    root.right = travel(root.right, low, high);
    return root;
}

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

力扣题目链接(opens new window)

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。

示例:

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

思路:递归法

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

一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1
因为数组升序排序
那么当数据元素为奇数,根节点只可能为最中间的结点。比如【-1,0,1,2,3】根节点为1
那么当数组元素为偶数,根节点只可能为最中间的两个结点。比如【-1,0,1,2】根节点为0,1.
递归法三要素
1.方法入参和返回值。入参:int[] nums 返回值TreeNode root
2.中止条件:数组的长度小于等于0,返回Null
3.核心逻辑
判断数组长度奇偶
长度为奇数,取最中间结点作为根节点,拆分左右数组
长度为偶数,取最中间结点中靠左或者靠右(这里为了保证左闭右开),拆分左右数组
对左右数组递归,root.left = 左数组返回结果,root.right = 右数组返回结果
返回root

代码如下

// 时间复杂度o(n)
// 空间复杂度o(n)
public TreeNode sortedArrayToBST(int[] nums) {
    return travel(nums);
}

public TreeNode travel(int[] nums) {
    if (nums.length <= 0) {// 中止条件
        return null;
    }

    TreeNode root;
    int[] leftNums;
    int[] rightNums;
    int index = (nums.length - 1) / 2;
    root = new TreeNode(nums[index], null, null);// 核心逻辑
    if (nums.length % 2 == 1) {
        leftNums = new int[index];
        rightNums = new int[index];
    } else {
        leftNums = new int[index];
        rightNums = new int[index + 1];
    }
    for (int i = 0; i < nums.length; i++) {
        if (i < index)
            leftNums[i] = nums[i];
        if (i > index)
            rightNums[i - index - 1] = nums[i];
    }
    root.left = travel(leftNums);
    root.right = travel(rightNums);

    return root;
}

思路:递归法优化

构造二叉树的时候尽量不要重新定义左右区间数组,而是用下标来操作原数组。
所以代码如下:

TreeNode* traversal(vector& nums, int left, int right)
确定递归终止条件
这里定义的是左闭右闭的区间,所以当区间 left > right的时候,就是空节点了。
代码如下:
if (left > right) return null;
取数组中间元素的位置,不难写出int mid = (left + right) / 2;,这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,在二分法 (opens new window)中尤其需要注意!
所以可以这么写:int mid = left + ((right - left) / 2);

代码如下

// 时间复杂度o(n)
// 空间复杂度o(n)
public TreeNode sortedArrayToBST(int[] nums) {
    TreeNode root = traversal(nums, 0, nums.length - 1);
    return root;
}

// 左闭右闭区间[left, right]
private TreeNode traversal(int[] nums, int left, int right) {
    if (left > right) return null;

    int mid = left + ((right - left) >> 1);
    TreeNode root = new TreeNode(nums[mid],null,null);
    root.left = traversal(nums, left, mid - 1);
    root.right = traversal(nums, mid + 1, right);
    return root;
}

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

力扣题目链接(opens new window)

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

节点的左子树仅包含键 小于 节点键的节点。 节点的右子树仅包含键 大于 节点键的节点。 左右子树也必须是二叉搜索树。

示例 1:

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

  • 输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
  • 输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

示例 2:

  • 输入:root = [0,null,1]
  • 输出:[1,null,1]

示例 3:

  • 输入:root = [1,0,2]
  • 输出:[3,3,2]

示例 4:

  • 输入:root = [3,2,4,1]
  • 输出:[7,9,4,10]

提示:

  • 树中的节点数介于 0 和 104 之间。
  • 每个节点的值介于 -104 和 104 之间。
  • 树中的所有值 互不相同 。
  • 给定的树为二叉搜索树。

思路:递归法(右中左)

这题目不好理解。将二叉搜索树中序遍历后的数组列出来,方便理解【1,2,3,4,5,6】
如果从数组的角度来说,这道题将数组从尾部做累加,双指针法即可。
找到二叉搜索树的某个结点比如说3,
比3大的值有4,5,6.
构建后的3结点值变更为3+4+5+6=18
那么数组大家都会,放到树上也是一个道理
我们定义pre指针保存树遍历的上一个结点val,遍历当前结点cur时,将结点的值做累加即可
遍历顺序为特殊的中序遍历(右中左)。因为这样才能保证遍历的结点顺序是由大到小

代码如下

// 时间复杂度o(n)
// 空间复杂度o(n)
int pre = 0;
public TreeNode convertBST(TreeNode root) {
    travel(root);
    return root;
}

public void travel(TreeNode cur){
    if(cur == null)
        return;
    travel(cur.right);
    if(pre != 0)
        cur.val = cur.val +pre;
    pre = cur.val;
    travel(cur.left);
    return;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值