代码随想录算法训练营第二十三天 | 669. 修剪二叉搜索树,108. 将有序数组转换为二叉搜索树,538. 把二叉搜索树转换为累加树,二叉树总结

669. 修剪二叉搜索树

这道题目比较难,比 添加增加和删除节点难的多,建议先看视频理解。

题目链接/文章讲解: 代码随想录

视频讲解: 你修剪的方式不对,我来给你纠正一下!| LeetCode:669. 修剪二叉搜索树_哔哩哔哩_bilibili

重点:

1. 二叉搜索树,根据当前节点的值可以知道把哪边子树当作根节点

思路:

递归法:

1. 确定参数及返回值

public TreeNode trimBST(TreeNode root, int low, int high)

2. 确定终止条件

if (root == null) { return null; }

3. 确定单层递归的逻辑

根据值的大小,递归的修剪左/右子树,然后回溯给上一层赋值即可

// 当前值小,修剪右子树
if (root.val < low) { return trimBST(root.right, low, high); }
// 当前值大,修剪左子树
if (root.val > high) { return trimBST(root.left, low, high); }
// 回溯给上一层以更换新节点
root.left = trimBST(root.left, low, high);
root.right = trimBST(root.right, low, high);

迭代法:

1. 不需要栈来模拟前中后序

2. 在剪枝的时候,可以分为三步:

  • 将root移动到[L, R] 范围内,注意是左闭右闭区间
  • 剪枝左子树
  • 剪枝右子树
public TreeNode trimBST(TreeNode root, int low, int high) {
        // 终止条件
        if (root == null) {
            return null;
        }
        // 单层递归的逻辑
        // 当前值小于low值,需要向右子树移动,但右子树可能也需要修剪
        if (root.val < low) {
            return trimBST(root.right, low, high);
        }
        // 当前值大于high值,需要向左子树移动,但左子树可能也需要修剪
        if (root.val > high) {
            return trimBST(root.left, low, high);
        }
        // 回溯,给左右子树赋值上新的节点
        root.left = trimBST(root.left, low, high);
        root.right = trimBST(root.right, low, high);
        return root;
}
public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) {
            return null;
        }
        // 先找到在区间的位置
        while (root != null && (root.val < low || root.val > high)) {
            if (root.val < low) {
                root = root.right;
            } else {
                root = root.left;
            }
        }
        TreeNode cur = root;
        // 开始修剪左子树
        while (cur != null) {
            while (cur.left != null && cur.left.val < low) {
                cur.left = cur.left.right;
            }
            cur = cur.left;
        }
        cur = root;
        // 开始修剪右子树
        while (cur != null) {
            while (cur.right != null && cur.right.val > high) {
                cur.right = cur.right.left;
            }
            cur = cur.right;
        }
        return root;
}

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

本题就简单一些,可以尝试先自己做做。

题目链接/文章讲解:代码随想录

视频讲解:构造平衡二叉搜索树!| LeetCode:108.将有序数组转换为二叉搜索树_哔哩哔哩_bilibili

重点;

1. 循环不变量原则,左闭右闭 / 左闭右开

思路:

递归法:

1. 确定参数及返回值

private TreeNode traversal(int[] nums, int leftIndex, int rightIndex)

2. 确定终止条件

当前这部分数组已经构成好子树了,所以才会index超标

if (leftIndex > rightIndex) { return null; }

3. 确定单层递归的逻辑

把数组分成前后两部分,递归的组成子树

int midIndex = (leftIndex + rightIndex) / 2;
TreeNode curRootNode = new TreeNode(nums[midIndex]);
// 左闭右闭
curRootNode.left = traversal(nums, leftIndex, midIndex - 1);
curRootNode.right = traversal(nums, midIndex + 1, rightIndex);
return curRootNode;
public TreeNode sortedArrayToBST(int[] nums) {
        if (nums.length == 0) {
            return null;
        }
        // 左闭右闭
        TreeNode root = traversal(nums, 0, nums.length - 1);
        return root;
}
private TreeNode traversal(int[] nums, int leftIndex, int rightIndex) {
        if (leftIndex > rightIndex) {
            return null;
        }
        int midIndex = (leftIndex + rightIndex) / 2;
        TreeNode curRootNode = new TreeNode(nums[midIndex]);
        // 左闭右闭
        curRootNode.left = traversal(nums, leftIndex, midIndex - 1);
        curRootNode.right = traversal(nums, midIndex + 1, rightIndex);
        return curRootNode;
}

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

本题也不难,在 求二叉搜索树的最小绝对差 和 众数 那两道题目 都讲过了 双指针法,思路是一样的。

题目链接/文章讲解:代码随想录

视频讲解:普大喜奔!二叉树章节已全部更完啦!| LeetCode:538.把二叉搜索树转换为累加树_哔哩哔哩_bilibili

重点:

1. 倒叙遍历有序数组可实现累加+双指针记录前一个节点即可

思路:

1. 确定参数及返回值

其实可以void,因为只是单纯的遍历全部节点,也并没有需要处理递归返回值

public TreeNode convertBST(TreeNode root)

2. 确定终止条件

if (root == null) { return null; }

3. 确定单层递归的逻辑

把中序倒过来遍历,就可以实现累加了,还要一个双指针来记录前一个节点

// 右
convertBST(root.right);
// 中
root.val += pre;
pre = root.val;
// 左
convertBST(root.left);

迭代法:

1. 用栈来记录遍历的顺序,但是因为我们要累加,所以是右中左来遍历

int pre = 0;
public TreeNode convertBST(TreeNode root) {
        if (root == null) {
            return null;
        }
        // 右
        convertBST(root.right);
        // 中
        root.val += pre;
        pre = root.val;
        // 左
        convertBST(root.left);
        return root;
}
int pre = 0;
public TreeNode convertBST(TreeNode root) {
        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()) {
            if (cur != null) {
                stack.offerLast(cur);
                // 右
                cur = cur.right;
            } else {
                // 中
                cur = stack.removeLast();
                cur.val += pre;
                pre = cur.val;
                // 左
                cur = cur.left;
            }
        }
        return root;
}

二叉树总结

二叉树的理论基础

二叉树的遍历方式

求二叉树的属性

二叉树的修改与构造

求二叉搜索树的属性

二叉树的公共祖先问题

二叉搜索树的修改与构造

阶段总结

大家以上题目都做过了,也一定要看如下阶段小结。

每周小结都会对大家的疑问做统一解答,并且对每周的内容进行拓展和补充,所以一定要看,将细碎知识点一网打尽!

最后总结

在二叉树题目选择什么遍历顺序是不少同学头疼的事情,我们做了这么多二叉树的题目了,Carl给大家大体分分类

  • 涉及到二叉树的构造,无论普通二叉树还是二叉搜索树一定前序,都是先构造中节点。

  • 求普通二叉树的属性,一般是后序,一般要通过递归函数的返回值做计算。

  • 求二叉搜索树的属性,一定是中序了,要不白瞎了有序性了。

注意在普通二叉树的属性中,我用的是一般为后序,例如单纯求深度就用前序,二叉树:找所有路径 (opens new window)也用了前序,这是为了方便让父节点指向子节点。

所以求普通二叉树的属性还是要具体问题具体分析。

二叉树专题汇聚为一张图:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值