代码随想录算法训练营第三期day23-二叉树09

目录

1. T669:修剪二叉树

1.1 法1、递归法

1.2 法2、迭代法

2. T108:将有序数组转换为BST

2.1 法1、递归

2.2 法2、迭代

3. T538:把BST转换为累加树

3.1 递归

3.2 迭代


1. T669:修剪二叉树

T669:给你二叉搜索树的根节点 root ,同时给定最小边界low 和最大边界 high。通过修剪二叉搜索树,使得所有节点的值在[low, high]中。修剪树 不应该 改变保留在树中的元素的相对结构 (即,如果没有被移除,原有的父代子代关系都应当保留)。 可以证明,存在 唯一的答案 。

所以结果应当返回修剪好的二叉搜索树的新的根节点。注意,根节点可能会根据给定的边界发生改变。

提示:

  • 树中节点数在范围 [1, 104] 内

  • 0 <= Node.val <= 104

  • 树中每个节点的值都是 唯一 的

  • 题目数据保证输入是一棵有效的二叉搜索树

  • 0 <= low <= high <= 104

S:

总结一句话:遇到不在指定区间内的节点A,就去找符合的节点,直到找到之后,就让符合的节点取代节点A成为子节点

1.1 法1、递归法

C++:

    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if (!root) return nullptr;
        if (root->val < low) {
            return trimBST(root->right, low, high);// 寻找符合区间[low, high]的节点
        } else if (root->val > high) {
            return trimBST(root->left, low, high);
        }
        root->left = trimBST(root->left, low, high);// root->left接入符合条件的左孩子
        root->right = trimBST(root->right, low, high);
        return root;
    }

Java:

    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) return null;
        if (root.val < low) {
            return trimBST(root.right, low, high);
        } else 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;
    }

1.2 法2、迭代法

迭代法里面还有几点没完全想清楚。。。(🚩处)

C++:

    TreeNode* trimBST(TreeNode* root, int low, int high) {
        if (!root) return nullptr;

        //处理头节点,让root移动到[L, R] 范围内,注意是左闭右闭
        while (root && (root->val < low || root->val > high)) {
            if (root->val < low) {
                root = root->right;
            } else {
                root = root->left;
            }
        }
        TreeNode* cur = root;
        // 此时root已经在[L, R] 范围内,处理左孩子元素小于L的情况
        while (cur) {//🚩如果没有这一行,error:[3] 2
            while (cur->left && cur->left->val < low) {
                cur->left = cur->left->right;
            }
            cur = cur->left;//🚩这一行的作用没看懂,没有就超时
        }
        cur = root;//一定要重新赋值!
        
        while (cur) {
            while (cur->right && cur->right->val > high) {
                cur->right = cur->right->left;
            }
            cur = cur->right;//这一行的作用没看懂
        }
        return root;
    }

Java:

    public TreeNode trimBST(TreeNode root, int low, int high) {
        if (root == null) return null;
        // while (root.val < low || root.val > high) {//🚩没标明root非空->error:[3] 2
        // while (root != null && root.val < low || root.val > high) {//没内层括号:error
        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) {//跟首个注释error的那行一样,必须有
            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;
    }

2. T108:将有序数组转换为BST

T108:给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

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

提示:

  • 1 <= nums.length <= 104

  • -104 <= nums[i] <= 104

  • nums 按 严格递增 顺序排列

S:只要每次都取中值做根节点,构造出的二叉树天然就会高度平衡~

2.1 法1、递归

C++:

//【左闭右闭】
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        // if (nums.size() == 0) return nullptr;
        return sortedArrayToBST(nums, 0, nums.size() - 1);
    }
private:
    TreeNode* sortedArrayToBST(vector<int>& nums, int left, int right) {
        if (left > right) return nullptr;//1、注意要不要=
        int mid = (left + right) / 2;
        // int mid = left + ((right - left) / 2);
        TreeNode* root = new TreeNode(nums[mid]);
        root->left = sortedArrayToBST(nums, left, mid - 1);
        root->right = sortedArrayToBST(nums, mid + 1, right);
        return root;
    }

//【左闭右开】
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        // if (nums.size() == 0) return nullptr;
        return sortedArrayToBST(nums, 0, nums.size());
    }
private:
    TreeNode* sortedArrayToBST(vector<int>& nums, int left, int right) {
        if (left >= right) return nullptr;//1、注意
        // if (right - left == 1) return new TreeNode(nums[0]);//2、犯傻
        if (right - left == 1) return new TreeNode(nums[left]);//其实没有这行也可以
        
        // int mid = left + ((right - left) >>> 1);//3、不知为何,用无符号右移就编译error,二分法都可以
        int mid = left + ((right - left) >> 1);
        TreeNode* root = new TreeNode(nums[mid]);
        root->left = sortedArrayToBST(nums, left, mid);
        root->right = sortedArrayToBST(nums, mid + 1, right);
        return root;
    }

Java:

//【左闭右闭】
    public TreeNode sortedArrayToBST(int[] nums) {
        return sortedArrayToBST(nums, 0, nums.length - 1);
    }
    private TreeNode sortedArrayToBST(int[] nums, int left, int right) {
        if (left > right) return null;
        int mid = left + ((right - left) >> 1);
        TreeNode root = new TreeNode(nums[mid]);
        root.left = sortedArrayToBST(nums, left, mid - 1);
        root.right = sortedArrayToBST(nums, mid + 1, right);
        return root;
    }

//【左闭右开】
    public TreeNode sortedArrayToBST(int[] nums) {
        return sortedArrayToBST(nums, 0, nums.length);
    }
    private TreeNode sortedArrayToBST(int[] nums, int left, int right) {
        if (left >= right) return null;
        int mid = left + ((right - left) >> 1);
        TreeNode root = new TreeNode(nums[mid]);
        root.left = sortedArrayToBST(nums, left, mid);
        root.right = sortedArrayToBST(nums, mid + 1, right);
        return root;
    }

2.2 法2、迭代

C++:

    TreeNode* sortedArrayToBST(vector<int>& nums) {
        if (nums.size() == 0) return nullptr;
        TreeNode* root = new TreeNode(nums[nums.size() / 2]);
        queue<TreeNode*> nodeQue;
        nodeQue.push(root);
        queue<int> leftQue;
        leftQue.push(0);
        queue<int> rightQue;
        rightQue.push(nums.size() - 1);
        while (!nodeQue.empty()) {
            TreeNode* curNode = nodeQue.front();
            nodeQue.pop();
            int left = leftQue.front();
            leftQue.pop();
            int right = rightQue.front();
            rightQue.pop();

            int mid = (left + right) / 2;
            curNode->val = nums[mid];// 【易漏】将mid对应的元素给中间节点

            if (left <= mid - 1) {// 处理左区间
                curNode->left = new TreeNode(0);
                nodeQue.push(curNode->left);
                leftQue.push(left);
                rightQue.push(mid - 1);
            }
            if (right >= mid + 1) {// 处理右区间
                curNode->right = new TreeNode(0);
                nodeQue.push(curNode->right);
                leftQue.push(mid + 1);
                rightQue.push(right);
            }
        }
        return root;
    }

Java:

    public TreeNode sortedArrayToBST(int[] nums) {
        if (nums.length == 0) return null;
        Deque<TreeNode> nodeQue = new LinkedList<>();
        TreeNode root = new TreeNode(0);
        nodeQue.push(root);
        Deque<Integer> leftQue = new LinkedList<>();
        leftQue.offerLast(0);
        Deque<Integer> rightQue = new LinkedList<>();
        rightQue.add(nums.length);
        while (!nodeQue.isEmpty()) {
            TreeNode curNode = nodeQue.pop();
            Integer left = leftQue.removeFirst();
            Integer right = rightQue.pollFirst();
            int mid = (left + right) / 2;
            curNode.val = nums[mid];// 【易漏】将mid对应的元素给中间节点
            
            // if (left <= mid) {//导致索引越界
            if (left < mid) {
                curNode.left = new TreeNode(nums[mid]);
                nodeQue.add(curNode.left);
                leftQue.add(left);
                rightQue.add(mid);
            }
            // if (right >= mid + 1) {
            if (right > mid + 1) {
                curNode.right = new TreeNode(nums[mid]);
                nodeQue.add(curNode.right);
                leftQue.add(mid + 1);
                rightQue.add(right);
            }
        }
        return root;
    }

3. T538:把BST转换为累加树

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

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

  • 节点的左子树仅包含键 小于 节点键的节点。

  • 节点的右子树仅包含键 大于 节点键的节点。

  • 左右子树也必须是二叉搜索树。

提示:

  • 树中的节点数介于 0 和 104 之间。

  • 每个节点的值介于 -104 和 104 之间。

  • 树中的所有值 互不相同 。

  • 给定的树为二叉搜索树。

S:虽然自己想着从左向右中序遍历,但实际上反中序遍历解起来更加便捷(不用每次都遍历所有大于自己的节点)

3.1 递归

C++:

    TreeNode* convertBST(TreeNode* root) {
        traversal(root);
        return root;
    }
private:
    int preSum;
    void traversal(TreeNode* cur) {
        if (!cur) return;
        traversal(cur->right);
        cur->val += preSum;
        preSum = cur->val;
        traversal(cur->left);
    }

Java:

    int preSum = 0;
    public TreeNode convertBST(TreeNode root) {
        traversal(root);
        return root;
    }
    private void traversal(TreeNode cur) {
        if (cur == null) return;
        traversal(cur.right);
        cur.val += preSum;
        preSum = cur.val;
        traversal(cur.left);
    }

3.2 迭代

C++:

//【普通迭代】
    TreeNode* convertBST(TreeNode* root) {
        int preSum = 0;
        TreeNode* cur = root;
        stack<TreeNode*> st;
        while (cur || !st.empty()) {
            if (cur) {
                st.push(cur);
                cur = cur->right;
            } else {
                // st.pop();
                cur = st.top();
                st.pop();
                cur->val += preSum;
                preSum = cur->val;
                cur = cur->left;
            }
        }
        return root;
    }


//【统一迭代】
    TreeNode* convertBST(TreeNode* root) {
        if (!root) return nullptr;
        stack<TreeNode*> st;
        st.push(root);
        int preSum = 0;
        while (!st.empty()) {
            TreeNode* cur = st.top();
            if (cur) {
                st.pop();
                if (cur->left) st.push(cur->left);
                st.push(cur);
                st.push(nullptr);
                if (cur->right) st.push(cur->right);
            } else {
                st.pop();
                cur = st.top();
                st.pop();
                cur->val += preSum;
                preSum = cur->val;
            }
        }
        return root;
    }

Java:

//【普通迭代】
    public TreeNode convertBST(TreeNode root) {
        int preSum = 0;
        Deque<TreeNode> stack = new LinkedList<>();
        TreeNode cur = root;
        while (cur != null || !stack.isEmpty()) {
            if (cur != null) {
                stack.push(cur);
                cur = cur.right;
            } else {
                cur = stack.pop();
                cur.val += preSum;
                preSum = cur.val;
                cur = cur.left;
            }
        }
        return root;
    }

//【统一迭代】
    public TreeNode convertBST(TreeNode root) {
        if (root == null) return null;
        int preSum = 0;
        Deque<TreeNode> stack = new LinkedList<>();
        stack.offerFirst(root);
        while (!stack.isEmpty()) {
            TreeNode cur = stack.pop();
            if (cur != null) {
                if (cur.left != null) stack.push(cur.left);
                stack.addFirst(cur);
                stack.addFirst(null);
                if (cur.right != null) stack.push(cur.right);
            } else {
                cur = stack.removeFirst();
                cur.val += preSum;
                preSum = cur.val;
            }
        }
        return root;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
代码随想录算法训练营是一个优质的学习和讨论平台,提供了丰富的算法训练内容和讨论交流机会。在训练营中,学员们可以通过观看视频讲解来学习算法知识,并根据讲解内容进行刷题练习。此外,训练营还提供了刷题建议,例如先看视频、了解自己所使用的编程语言、使用日志等方法来提高刷题效果和语言掌握程度。 训练营中的讨论内容非常丰富,涵盖了各种算法知识点和解题方法。例如,在第14天的训练营中,讲解了二叉树的理论基础、递归遍历、迭代遍历和统一遍历的内容。此外,在讨论中还分享了相关的博客文章和配图,帮助学员更好地理解和掌握二叉树的遍历方法。 训练营还提供了每日的讨论知识点,例如在第15天的讨论中,介绍了层序遍历的方法和使用队列来模拟一层一层遍历的效果。在第16天的讨论中,重点讨论了如何进行调试(debug)的方法,认为掌握调试技巧可以帮助学员更好地解决问题和写出正确的算法代码。 总之,代码随想录算法训练营是一个提供优质学习和讨论环境的平台,可以帮助学员系统地学习算法知识,并提供了丰富的讨论内容和刷题建议来提高算法编程能力。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [代码随想录算法训练营每日精华](https://blog.csdn.net/weixin_38556197/article/details/128462133)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值