第二十一天|二叉搜索树的属性,修改与构造,二叉树章节总结| 669. 修剪二叉搜索树,108. 将有序数组转换为二叉搜索树,538. 把二叉搜索树转换为累加树

目录

669. 修剪二叉搜索树

递归法(需掌握)

迭代法

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

递归法(简单)

迭代法

538. 把二叉搜索树转换为累加树(需再看!掌握,简单)

递归法(需掌握)

迭代法

二叉树总结


本节的三道题都蛮好的,不是很难,但是自己也没法完全写出来,需要再看再尝试!

以后做题先试递归法

669. 修剪二叉搜索树

669递归法代码写出来好简洁,自己思考的时候很混乱,多看一下!

[1, 3]区间在二叉搜索树的中可不是单纯的节点3和左孩子节点0就决定的,还要考虑节点0的右子树。

递归法(需掌握)

  • 确定单层递归的逻辑

        如果root(当前节点)的元素小于low的数值,那么应该递归右子树(因为右子树中存在不符合要求的节点),并返回右子树符合条件的头结点。

        如果root(当前节点)的元素大于high的,那么应该递归左子树,并返回左子树符合条件的头结点。

        然后将下一层处理完左子树的结果赋给root->left,处理完右子树的结果赋给root->right。

        最后返回root节点。

    class Solution {
        public TreeNode trimBST(TreeNode root, int low, int high) {
            // 递归法
            if (root == null) return null;
            if (root.val < low) {
                return trimBST(root.right, low, high);
            }
            if (root.val > high) {
                return trimBST(root.left, low, high);
            }
            // root在[low,high]范围内
            root.left = trimBST(root.left, low, high);
            root.right = trimBST(root.right, low, high);
            return root;
        }
    }

迭代法

因为二叉搜索树的有序性,不需要使用栈模拟递归的过程。

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

  • 将root移动到[L, R] 范围内,注意是左闭右闭区间
  • 剪枝左子树
  • 剪枝右子树

逐步修剪不符合条件的节点,确保每个节点都在指定范围内。

    class Solution {
        public TreeNode trimBST(TreeNode root, int low, int high) {
            // 迭代法
            if (root == null) return null;
            // 处理头结点,让root移动到[L, R] 范围内,注意是左闭右闭
            while (root != null && (root.val < low || root.val > high)) {
                if (root.val < low)
                    root = root.right;
                else
                    root = root.left;
            }
            TreeNode curr = root;
            while (curr != null) { // 处理左子树
                while (curr.left != null && curr.left.val < low) {
                    curr.left = curr.left.right; // 检查 curr.left 是否存在且值小于 low,如果是,就将 curr.left 更新为其右子树
                }
                curr = curr.left;
            }
            //go back to root
            curr = root;
            while (curr != null) { // 处理右子树
                while (curr.right != null && curr.right.val > high) {
                    curr.right = curr.right.left;
                }
                curr = curr.right;
            }
            return root;
        }
    }

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

本题注意是  平衡 二叉搜索树

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

本题就是寻找分割点,分割点作为当前节点,然后递归左区间和右区间。分割点就是数组中间位置的节点。

递归法(简单)

递归三部曲:

  • 确定递归函数返回值及其参数

(在构造二叉树的时候尽量不要重新定义左右区间数组,而是用下标来操作原数组。)

// 左闭右闭区间[left, right]
TreeNode* traversal(vector<int>& nums, int left, int right)
  • 确定递归终止条件

这里定义的是左闭右闭的区间,所以当区间 left > right的时候,就是空节点了。

if (left > right) return nullptr;
  • 确定单层递归的逻辑

首先取数组中间元素的位置,不难写出int mid = (left + right) / 2;这么写其实有一个问题,就是数值越界,例如left和right都是最大int,这么操作就越界了,在二分法中尤其需要注意!

所以可以这么写:int mid = left + ((right - left) / 2);但本题leetcode的测试数据并不会越界,所以怎么写都可以。但需要有这个意识!

    class Solution {
        public TreeNode sortedArrayToBST(int[] nums) {
            // 递归法: 左闭右闭 [left,right]
            TreeNode root = traversal(nums, 0, nums.length - 1);
            return root;
        }

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

迭代法

没搞懂这道题的迭代法的逻辑。以及最后返回root等等。可能受限于现在的JAVA基础没学完。

看递归法吧,好理解。后续再来理解一下迭代法。

    class Solution {
        public TreeNode sortedArrayToBST(int[] nums) {
            // 迭代法: 左闭右闭 [left,right]
            if (nums.length == 0) return null;
            //根节点初始化
            TreeNode root = new TreeNode(-1); // 值初始化为 -1(实际上这个值在后面会被替换)。这是为了方便后续操作。
            Queue<TreeNode> nodeQueue = new LinkedList<>(); //存储待处理的树节点。
            Queue<Integer> leftQueue = new LinkedList<>(); //存储对应节点的左右区间的下标。
            Queue<Integer> rightQueue = new LinkedList<>();
            // 根节点入队列
            nodeQueue.offer(root);
            // 0为左区间下标初始位置
            leftQueue.offer(0);
            // nums.size() - 1为右区间下标初始位置
            rightQueue.offer(nums.length - 1);

            while (!nodeQueue.isEmpty()) {
                // 取出当前节点及其左右区间下标。
                TreeNode currNode = nodeQueue.poll();
                int left = leftQueue.poll();
                int right = rightQueue.poll();
                int mid = left + (right - left) / 2;
                // 将mid对应的元素给中间节点
                currNode.val = nums[mid];
                // 处理左区间
                if (left <= mid - 1) {
                    currNode.left = new TreeNode(-1);
                    nodeQueue.offer(currNode.left);
                    leftQueue.offer(left);
                    rightQueue.offer(mid - 1);
                }
                // 处理右区间
                if (right >= mid + 1) {
                    currNode.right = new TreeNode(-1);
                    nodeQueue.offer(currNode.right);
                    leftQueue.offer(mid + 1);
                    rightQueue.offer(right);
                }
            }
            return root;
        }
    }

538. 把二叉搜索树转换为累加树(需再看!掌握,简单

这道题说实话我自己都没看懂题目是啥意思。看了题解后才搞懂。

一棵树,换一个角度来看,这就是一个有序数组[2, 5, 13],求从后到前的累加数组,也就是[20, 18, 13]。

思路:从树中可以看出累加的顺序是右中左,所以我们需要反中序遍历这个二叉树,然后顺序累加就可以了

递归法(需掌握)

双指针操作:pre,cur。

需要一个pre指针记录当前遍历节点cur的前一个节点,这样才方便做累加。

注意要右中左来遍历二叉树, 中节点的处理逻辑就是让cur的数值加上前一个节点的数值。

用sum一样的。

    class Solution {
        int sum;

        public TreeNode convertBST(TreeNode root) {
            // 递归法
            sum = 0;
            convertBST1(root);
            return root;
        }

        // 按右中左顺序遍历,累加即可
        public void convertBST1(TreeNode root) {
            if (root == null) return;
            convertBST1(root.right); // 右
            sum += root.val;         // 中
            root.val = sum;
            convertBST1(root.left);  // 左
        }
    }

迭代法

迭代法其实就是中序模板题

    class Solution {
        public TreeNode convertBST(TreeNode root) {
            // 迭代法
            int pre = 0;
            Stack<TreeNode> stack = new Stack<>();
            if (root == null) return null;
            stack.add(root);
            while (!stack.isEmpty()) {
                TreeNode curr = stack.peek();
                //curr != null的状况,只负责存node到stack中
                if (curr != null) {
                    stack.pop();
                    if (curr.left != null)       //左
                        stack.add(curr.left);
                    stack.add(curr);             //中
                    stack.add(null);
                    if (curr.right != null)      //右
                        stack.add(curr.right);
                } else {
                    //curr == null的状况,只负责做单层逻辑
                    stack.pop();
                    TreeNode temp = stack.pop();
                    temp.val += pre;
                    pre = temp.val;
                }
            }
            return root;
        }
    }

二叉树总结

二叉树总结篇看这里:二叉树总结

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

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

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

后续复盘有空再来做这几道。

589. N叉树的前序遍历

590. N叉树的后序遍历

100.相同的树

572.另一个树的子树

二叉树终于结束了!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

第二十一天的总算是结束了,直冲Day22!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值