LC.938 | 二叉搜索树的范围和 | 树 | BST中序遍历

输入:
二叉搜索树的根节点 root,以及两个整数 lowhigh

要求:
计算树中所有值在 [low, high] 范围内的节点值之和。

输出:
一个整数,表示范围和。


思路:

这道题表面是树的遍历,内里藏着 二叉搜索树(BST) 最核心的“降维打击”思维。

1. 核心公式:BST + 中序遍历 = 有序数组

我们必须把这个公式刻在脑子里:二叉搜索树的中序遍历结果,就是严格递增的有序数组
当你面对一棵复杂的二维 BST 时,只要在脑海中对它做一次中序遍历,它立刻就“坍缩”成了一个简单的一维有序数组。

  • 本题要求的 [low, high] 范围和,本质上就是在问:在这个隐形的有序数组中,截取中间符合范围的一段进行求和。

2. 为什么这就叫“降维打击”?

一旦你理解了上述本质,BST 的问题就全部变成了简单的数组问题。以下是四大经典场景(全是 LeetCode 高频题),你会发现它们本质上都是同一道题:

  • 场景一:验证合法性 (LC.98)
    • 数组视角:一个合法的有序数组必须是严格递增的。
    • 解法:中序遍历,只要检查 current->val > prev->val。一旦出现乱序(逆序),直接返回 false。
  • 场景二:找第 K 小 (LC.230)
    • 数组视角:有序数组里第 K 个数是谁?
    • 解法:中序遍历自带排序,只需要一个计数器 count,数到第 K 个直接返回,连数组都不用存。
  • 场景三:恢复错乱数据 (LC.99)
    • 数组视角:有序排队的队伍里,有两个人的位置站反了(逆序对)。
    • 解法:中序遍历找“逆序对”。第一次遇到前大后小记录“大个子”,第二次遇到记录“小个子”,交换即可。
  • 场景四:累加树 (LC.538)
    • 数组视角:要把数组变成前缀和(或后缀和)。
    • 解法反向中序遍历(右->根->左)。这就相当于从数组最大的屁股后面往前遍历,一路累加,降维打击。

3. 回到本题 (LC.938)

本题就是上述思想的**“剪枝版”**。我们不需要真的把整个数组遍历出来,因为我们知道数组的头(小于 low)和尾(大于 high)是我们不需要的。

  • 当前节点 < low:说明我们在有序数组的左侧,太小了,往右走(相当于抛弃数组左半边)。
  • 当前节点 > high:说明我们在有序数组的右侧,太大了,往左走(相当于抛弃数组右半边)。
  • 命中范围:说明我们在数组中间的有效段,累加并继续探索。

复杂度:

  • 时间复杂度:O(N)
    • 在最坏情况下需要遍历所有节点,但利用“有序数组”的思维进行剪枝,往往能屏蔽掉大量无效节点。
  • 空间复杂度:O(H)
    • 递归栈的深度。

class Solution {
public:
    // 这里的 DFS 实际上就是在模拟在一个“有序数组”中筛选数据的过程
    void dfs(TreeNode* node, int low, int high, int& ans) {
        if (!node) {
            return;
        }
        
        // 1. 如果当前节点在 [low, high] 之间
        // 相当于我们在有序数组的“有效片段”中
        if (node->val >= low && node->val <= high) {
            ans += node->val;
            
            // 只有当 node->val > low 时,左边才可能还有有效数字(还没触底)
            if (node->val > low) dfs(node->left, low, high, ans);
            
            // 只有当 node->val < high 时,右边才可能还有有效数字(还没触顶)
            if (node->val < high) dfs(node->right, low, high, ans);
        }
        // 2. 如果当前节点 < low
        // 说明我们在有序数组的左端,且当前位置太小了,左边的更小,肯定全废了
        // 直接跳到右边去
        else if (node->val < low) {
            dfs(node->right, low, high, ans);
        }
        // 3. 如果当前节点 > high
        // 说明我们在有序数组的右端,且当前位置太大了,右边的更大,肯定全废了
        // 直接跳到左边去
        else if (node->val > high) {
            dfs(node->left, low, high, ans);
        }
    }

    int rangeSumBST(TreeNode* root, int low, int high) {
        int ans = 0;
        dfs(root, low, high, ans);
        return ans;
    }
};                         
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值