day21 代码随想录算法训练营 二叉树专题8

1 今日打卡题

修剪二叉搜索树 669. 修剪二叉搜索树 - 力扣(LeetCode)

将有序数组转换为二叉树 108. 将有序数组转换为二叉搜索树 - 力扣(LeetCode)

把二叉搜索树转换为累加树 538. 把二叉搜索树转换为累加树 - 力扣(LeetCode)

2 修剪二叉搜索树

2.1 思路

如果当前节点值大于 high,说明当前节点及其右子树都不符合条件,只需递归处理左子树并返回;

如果当前节点值小于 low,说明当前节点及其左子树都不符合条件,只需递归处理右子树并返回;

如果当前节点值在 [low, high] 范围内,则保留该节点,递归修剪其左、右子树后拼接到当前节点上,最后返回当前节点;

递归终止条件:遇到空节点时直接返回 null。

核心逻辑:利用 BST 的特性减少无效递归(节点值超限时,直接跳过一侧子树),递归修剪符合条件的节点;

递归终止:遇到空节点返回 null;

节点保留规则:值在 [low, high] 范围内时,保留节点并递归修剪其左右子树;值超限则返回另一侧子树的修剪结果。

2.2 实现代码

java 复制代码
class Solution {
    /**
     * 修剪二叉搜索树,只保留值在 [low, high] 范围内的节点
     * @param root 二叉搜索树的根节点
     * @param low 下限值
     * @param high 上限值
     * @return 修剪后的二叉搜索树根节点
     */
    public TreeNode trimBST(TreeNode root, int low, int high) {
        // 递归终止条件:当前节点为空,直接返回null
        if(root == null) return null;
        
        // 情况1:当前节点值大于high,根据BST特性,其右子树所有节点都大于high,无需处理
        // 只需递归修剪左子树,并返回左子树修剪后的结果
        if(root.val > high) {
            TreeNode left = trimBST(root.left, low, high);
            return left;
        }
        
        // 情况2:当前节点值小于low,根据BST特性,其左子树所有节点都小于low,无需处理
        // 只需递归修剪右子树,并返回右子树修剪后的结果
        if(root.val < low) {
            TreeNode right = trimBST(root.right, low, high);
            return right;
        }
        
        // 情况3:当前节点值在[low, high]范围内,保留该节点
        // 递归修剪左子树,将修剪后的左子树赋值给当前节点的左孩子
        root.left = trimBST(root.left, low, high);
        // 递归修剪右子树,将修剪后的右子树赋值给当前节点的右孩子
        root.right = trimBST(root.right, low, high);
        
        // 返回保留的当前节点(已完成左右子树的修剪)
        return root;
    }
}

模拟:

修剪范围:low=1,high=3(只保留值为 1、2、3 的节点)。

执行步骤:

调用 trimBST(3, 1, 3):

3 在 [1,3] 范围内,先处理左子树(节点 0),再处理右子树(节点 4)。

处理左子树:调用 trimBST(0, 1, 3):

0 < 1,需要递归处理其右子树(节点 2),返回右子树的修剪结果。

调用 trimBST(2, 1, 3):

2 在 [1,3] 范围内,处理左子树(节点 1),右子树为空(返回 null)。

调用 trimBST(1, 1, 3):

1 在 [1,3] 范围内,左右子树都为空,返回节点 1。

回到节点 2 的处理:

节点 2 的左孩子赋值为节点 1,右孩子为 null,返回节点 2。

回到节点 0 的处理:

节点 0 < 1,返回节点 2(其右子树的修剪结果),因此节点 3 的左孩子变为节点 2。

处理节点 3 的右子树:调用 trimBST(4, 1, 3):

4 > 3,递归处理其左子树(为空),返回 null,因此节点 3 的右孩子为 null。

最终返回节点 3,修剪后的树结构:

3 将有序数组转换为二叉树

3.1 思路

递归终止条件:当左指针 > 右指针时,说明当前子树无节点,返回 null;

确定根节点:取数组中间位置 mid 的元素作为当前子树的根节点;

构建左子树:递归处理数组左半部分 [left, mid-1],作为根节点的左子树;

构建右子树:递归处理数组右半部分 [mid+1, right],作为根节点的右子树;

返回当前根节点:完成当前子树的构建并返回。

3.2 实现代码

java 复制代码
class Solution {
    // 主方法:将有序数组转换为平衡二叉搜索树
    public TreeNode sortedArrayToBST(int[] nums) {
        // 调用递归构建方法,初始范围是整个数组(左边界0,右边界nums.length-1)
        TreeNode root = build(nums, 0, nums.length - 1);
        return root;
    }

    // 递归构建方法:参数为数组、当前子树对应的数组左边界、右边界
    public TreeNode build(int[] nums, int left, int right) {
        // 递归终止条件:左边界超过右边界,说明当前子树无节点,返回null
        if (left > right) {
            return null;
        }

        // 1. 找中间位置作为根节点(保证左右子树节点数尽可能相等,平衡)
        int mid = (left + right) / 2;
        // 2. 创建当前子树的根节点(值为中间位置的元素)
        TreeNode root = new TreeNode(nums[mid]);
        // 3. 递归构建左子树:范围是[left, mid-1],挂到当前根节点的左孩子
        root.left = build(nums, left, mid - 1);
        // 4. 递归构建右子树:范围是[mid+1, right],挂到当前根节点的右孩子
        root.right = build(nums, mid + 1, right);

        // 返回当前构建好的子树根节点
        return root;
    }
}

4 把二叉搜索树转换为累加树

4.1 思路

要实现累加,关键是逆中序遍历 (右→根→左):

先遍历右子树(值更大的节点),再处理当前节点,最后遍历左子树;

用一个全局 / 引用变量记录 "累加和",遍历到当前节点时,将累加和赋值给当前节点,再把当前节点原值加到累加和中;

递归终止条件:遇到空节点直接返回。

4.2 实现代码

java 复制代码
class Solution {
    // 全局变量:记录累加和(初始为0)
    private int sum = 0;

    public TreeNode convertBST(TreeNode root) {
        // 递归入口:逆中序遍历整棵树
        traversal(root);
        return root;
    }

    // 逆中序遍历函数(右→根→左)
    private void traversal(TreeNode node) {
        // 递归终止:节点为空,直接返回
        if (node == null) {
            return;
        }

        // 1. 先遍历右子树(值更大的节点)
        traversal(node.right);

        // 2. 处理当前节点:累加和赋值给当前节点,再更新累加和
        sum += node.val; // 累加和 = 原有累加和 + 当前节点原值
        node.val = sum;  // 当前节点新值 = 累加和

        // 3. 再遍历左子树(值更小的节点)
        traversal(node.left);
    }
}
相关推荐
Fleshy数模44 分钟前
多分类任务下的经典机器学习算法实战:LR、RF、SVM等对比分析
算法·机器学习·分类
风吹乱了我的头发~4 小时前
Day52:2026年3月20日打卡
算法
2401_831824968 小时前
基于C++的区块链实现
开发语言·c++·算法
We་ct8 小时前
LeetCode 918. 环形子数组的最大和:两种解法详解
前端·数据结构·算法·leetcode·typescript·动态规划·取反
愣头不青9 小时前
238.除了自身以外数组的乘积
数据结构·算法
人工智能AI酱9 小时前
【AI深究】逻辑回归(Logistic Regression)全网最详细全流程详解与案例(附大量Python代码演示)| 数学原理、案例流程、代码演示及结果解读 | 决策边界、正则化、优缺点及工程建议
人工智能·python·算法·机器学习·ai·逻辑回归·正则化
WangLanguager9 小时前
逻辑回归(Logistic Regression)的详细介绍及Python代码示例
python·算法·逻辑回归
m0_518019489 小时前
C++与机器学习框架
开发语言·c++·算法
一段佳话^cyx9 小时前
详解逻辑回归(Logistic Regression):原理、推导、实现与实战
大数据·算法·机器学习·逻辑回归
qq_417695059 小时前
C++中的代理模式高级应用
开发语言·c++·算法