当前位置: 首页 > news >正文

今日算法(二叉搜索树)

题目描述

给定一棵二叉搜索树(BST)的根节点root,树中节点值各不相同。要求将其转换为累加树(Greater Sum Tree),规则如下:

  • 每个节点的新值 = 原节点值 + 所有比它大的节点值的总和
  • 二叉搜索树的性质:
    • 左子树所有节点值 < 根节点值
    • 右子树所有节点值 > 根节点值
    • 中序遍历结果为升序序列

核心思路:逆中序遍历 + 累加

要实现累加树,关键是从大到小遍历所有节点,边遍历边累加,再更新当前节点的值。

核心逻辑

二叉搜索树的 ** 中序遍历(左 - 根 - 右)是升序,那么逆中序遍历(右 - 根 - 左)** 就是降序。

  • 我们按降序遍历所有节点,用一个变量sum记录遍历过的节点值总和
  • 每次访问一个节点时,先更新sum(加上当前节点值),再把sum赋值给当前节点
  • 这样就能保证每个节点的值 = 原节点值 + 所有比它大的节点值的和

完整代码实现(C++)

cpp

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: // 全局变量,记录遍历过程中的累加和 int sum = 0; TreeNode* convertBST(TreeNode* root) { // 逆中序遍历:右 -> 根 -> 左 if (root != nullptr) { // 1. 先遍历右子树(所有比当前节点大的节点) convertBST(root->right); // 2. 处理当前节点:更新累加和,并修改节点值 sum += root->val; root->val = sum; // 3. 再遍历左子树(所有比当前节点小的节点) convertBST(root->left); } return root; } };

详细执行流程解析

我们以示例root = [4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]为例,模拟逆中序遍历过程:

初始状态

  • sum = 0
  • 节点值(升序):0, 1, 2, 3, 4, 5, 6, 7, 8
  • 逆序遍历顺序:8 → 7 → 6 → 5 → 4 → 3 → 2 → 1 → 0

遍历过程

  1. 访问节点8
    • sum += 8sum = 8
    • root->val = 8(节点值更新为 8)
  2. 访问节点7
    • sum += 7sum = 15
    • root->val = 15(节点值更新为 15)
  3. 访问节点6
    • sum += 6sum = 21
    • root->val = 21(节点值更新为 21)
  4. 访问节点5
    • sum += 5sum = 26
    • root->val = 26(节点值更新为 26)
  5. 访问节点4
    • sum += 4sum = 30
    • root->val = 30(节点值更新为 30)
  6. 访问节点3
    • sum += 3sum = 33
    • root->val = 33(节点值更新为 33)
  7. 访问节点2
    • sum += 2sum = 35
    • root->val = 35(节点值更新为 35)
  8. 访问节点1
    • sum += 1sum = 36
    • root->val = 36(节点值更新为 36)
  9. 访问节点0
    • sum += 0sum = 36
    • root->val = 36(节点值更新为 36)

最终结果

所有节点值更新为:[30, 36, 21, 36, 35, 26, 15, null, null, null, 33, null, null, null, 8],和示例输出完全一致。


关键细节与易错点

  1. 逆中序遍历的顺序必须严格按照右子树 → 根节点 → 左子树的顺序遍历,这样才能保证先访问所有比当前节点大的节点,再更新当前节点的值。

  2. 累加和变量sum的作用sum是一个全局变量(或通过引用传递的变量),记录所有已经访问过的节点值的总和,每次更新节点值时,直接赋值sum即可,无需重复计算。

  3. 空节点的处理root == nullptr时,直接返回,不做任何操作,这是递归的终止条件。

  4. 节点值的修改顺序必须先更新sum,再修改root->val,否则会导致节点值更新错误。


复杂度分析

  • 时间复杂度:\(O(n)\),其中 n 为树的节点数。每个节点只会被访问一次。
  • 空间复杂度:\(O(h)\),其中 h 为树的高度。递归调用栈的深度等于树的高度,最坏情况下(树退化为链表)为 \(O(n)\)。

拓展:迭代版实现(可选)

如果不想使用递归,可以用栈模拟逆中序遍历:

cpp

class Solution { public: TreeNode* convertBST(TreeNode* root) { int sum = 0; stack<TreeNode*> stk; TreeNode* cur = root; // 逆中序遍历:右-根-左 while (cur != nullptr || !stk.empty()) { // 1. 一直向右走,把所有右子树节点压入栈 while (cur != nullptr) { stk.push(cur); cur = cur->right; } // 2. 弹出栈顶节点(当前访问的节点) cur = stk.top(); stk.pop(); // 3. 更新累加和,并修改节点值 sum += cur->val; cur->val = sum; // 4. 处理左子树 cur = cur->left; } return root; } };

总结

将二叉搜索树转换为累加树的核心,就是利用逆中序遍历的降序特性,边遍历边累加更新节点值。这种方法无需额外空间,仅通过一次遍历就能完成转换,时间复杂度为线性,是最优解之一。

http://www.jsqmd.com/news/866904/

相关文章:

  • Linux服务器故障排查:从连不上到查得清的归因路径
  • Midscene.js终极指南:如何用AI视觉驱动技术彻底改变UI自动化测试
  • 如何用Autolabel在5分钟内完成数据标注:面向新手的终极实战指南
  • 别再瞎找了!盘点2026年碾压级的的降AIGC网站
  • 从api密钥管理与审计日志看taotoken的企业级安全特性
  • TVA凭什么成为”数字AI“通往”物理AI“的关键桥梁(7)
  • OpenISP 模块拆解 · 第14讲:伪彩抑制 (FCS)
  • DeepSeek-R1 vs Qwen2.5 vs Claude-3:17项硬指标对比,谁才是2024高性价比AI模型黑马?
  • Source Sans 3:让数字界面阅读体验焕然一新的开源字体解决方案
  • 技术新人的“学习路径图”:别一上来就啃源码
  • OpenISP 模块拆解 · 第15讲:色相饱和度控制 (HSC)
  • Cardboard XR Plugin实战指南:轻量级Android VR落地方案
  • Godot常见问题排查指南:信号连接、资源加载与导出配置实战
  • Unity极地纹理包实战指南:从贴图到环境生成引擎
  • 【独家首发】DeepSeek-VL与R1双模型事实校验对照实验:1276条权威知识链验证,误差分布首次公开
  • ORK Framework 3:Unity RPG可视化逻辑建模与系统解耦实践
  • Agent记忆系统工程:让AI真正记住重要的事
  • 免费图片去水印工具怎么选?2026年在线软件全面对比与推荐指南
  • ZFS修复不是fsck:状态回溯与三重校验机制解析
  • 设备码钓鱼攻击产业化扩散机理与闭环防御体系研究
  • OpenISP 模块拆解 · 第16讲:亮度对比度控制 (BCC)
  • Unity运行时几何切割:OpenFracture物理可信破碎方案
  • TVA凭什么成为”数字AI“通往”物理AI“的关键桥梁(8)
  • 自由职业者的合同模板:保护自己的六个关键条款
  • python民宿预定信息退订系统
  • Unity第三人称射击原型:Playmaker可视化逻辑解剖
  • Unity脚本智能生成与一键部署工作流
  • Unity手机变无线触摸板:UDP低延迟输入注入实战
  • 如何快速解密QQ音乐QMC格式音频文件?
  • 2026年5月最新哈尔滨黄金回收白银回收铂金回收权威排行榜TOP5:纯金+金条+银条+钯金 门店地址联系方式推荐 - 检测回收中心