Leetcode 538. 把二叉搜索树转换为累加树(Morris 遍历)

news/2024/11/29 8:45:53/
  • Leetcode 538. 把二叉搜索树转换为累加树(Morris 遍历)
  • 题目
    • 给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。
    • 提醒一下,二叉搜索树满足下列约束条件:
      • 节点的左子树仅包含键 小于 节点键的节点。
      • 节点的右子树仅包含键 大于 节点键的节点。
      • 左右子树也必须是二叉搜索树。
    • 树中的节点数介于 0 和 10^4 之间。
    • 每个节点的值介于 -10^4 和 10^4 之间。
    • 树中的所有值 互不相同 。
    • 给定的树为二叉搜索树。
  • 解法
    • 累加树本质上就是从最后一个元素往前,每个元素加上前面所有元素 val 的和
    • 循环、Morris 遍历:核心思想是修改树的空指针,实现树型转化为数组型方便遍历,此时空间就能极限压缩。反中序遍历规则总结如下:
      1. 如果当前节点的右子节点为空,当前节点就累加上,然后移动到当前节点的左子节点(可通过"虚拟左子节点"回到前驱)
      2. 如果当前节点的右子节点不为空,找到当前节点右子树的"真实左子节点"的最后一个、称为最左子节点(该节点为当前节点反中序遍历的前驱节点)
        • 如果最左子节点的"虚拟左子节点"为空,将最左节点的"虚拟左子节点"指向当前节点(修改树添加"虚拟左子节点",指向前驱、用于"回溯"),然后移动到当前节点的右子节点
        • 如果最左子节点的"虚拟左子节点"不为空,将"虚拟左子节点"重新置为空(恢复树的原状删除"虚拟左子节点",右子树完成),当前节点就累加上,然后移动到当前节点的左子节点
      3. 重复步骤 1 和步骤 2,直到遍历结束。
    • 时间复杂度:O(n)每个点最多访问两次,空间复杂度:O(1)
  • 代码
    /*** 累加树本质上就是从最后一个元素往前,每个元素加上前面所有元素 val 的和* 循环、Morris 遍历:核心思想是修改树的空指针,实现树型转化为数组型方便遍历,此时空间就能极限压缩。反中序遍历规则总结如下:* 1. 如果当前节点的右子节点为空,当前节点就累加上,然后移动到当前节点的左子节点(可通过"虚拟左子节点"回到前驱)* 2. 如果当前节点的右子节点不为空,找到当前节点右子树的"真实左子节点"的最后一个、称为最左子节点(该节点为当前节点反中序遍历的前驱节点)*     如果最左子节点的"虚拟左子节点"为空,将最左节点的"虚拟左子节点"指向当前节点(修改树添加"虚拟左子节点",指向前驱、用于"回溯"),然后移动到当前节点的右子节点*     如果最左子节点的"虚拟左子节点"不为空,将"虚拟左子节点"重新置为空(恢复树的原状删除"虚拟左子节点",右子树完成),当前节点就累加上,然后移动到当前节点的左子节点* 3. 重复步骤 1 和步骤 2,直到遍历结束。* 时间复杂度:O(n)每个点最多访问两次,空间复杂度:O(1)*/private TreeNode solution2(TreeNode root) {// 判空if (root == null) {return root;}// 从根节点开始 Morris 遍历TreeNode cur = root;int sum = 0;while (cur != null) {// 当前节点的右子节点为空if (cur.right == null) {// 当前节点累加sum += cur.val;cur.val = sum;// 移动到左子节点(可通过"虚拟左子节点"回到前驱)cur = cur.left;// 如果当前节点的右子节点不为空} else {// 找到当前节点反中序遍历的前驱节点TreeNode prev = getTreePrevious(cur);// "虚拟左子节点"为空if (prev.left == null) {// "虚拟左子节点"指向当前节点prev.left = cur;// 然后移动到当前节点的右子节点cur = cur.right;// "虚拟左子节点"不为空} else {// "虚拟左子节点"重新置为空prev.left = null;// 当前节点就累加sum += cur.val;cur.val = sum;// 然后移动到当前节点的左子节点cur = cur.left;}}}return root;}/*** 找到当前节点反中序遍历的前驱节点* @param cur cur 节点存在右子节点*/private TreeNode getTreePrevious(TreeNode cur) {TreeNode prev = cur.right;// "虚拟左子节点"不能返回while (prev.left != null && prev.left != cur) {prev = prev.left;}return prev;}

http://www.ppmy.cn/news/76481.html

相关文章

【22-23春】AI作业10-经典卷积网络

1.LeNet & MNIST LeNet是一种神经网络的模型,用于图像识别和分类。他包含 3 个卷积层,2 个池化层,1 个全连接层。其中所有卷积层的所有卷积核都为 5x5,步长 strid1,池化方法都为全局 pooling,激活函数…

05 JDBC基础

什么是持久化 将内存中的数据永久保存在磁盘中,方便以后使用 JDBC是什么 java数据库连接 用于执行sql语句的java API java官方提供接口,各大厂商提供实现类,程序员使用实现类的jar包 JDBC的开发流程 添加包: mysql-connector-java-5.1.48.jar lombok.jar 口诀:贾连欲…

Windows操作系统的文件组织结构和计算方法

我是荔园微风,作为一名在IT界整整25年的老兵,今天总结一下Windows操作系统的文件组织结构和计算方法。 这是一块非常实用的知识,感谢大家来看这个帖子。 Windows组织结构就是文件的组织形式,其中: 1.Windows逻辑结构…

java+springboot留学生新闻资讯网的设计与实现

Spring框架是Java平台的一个开放源代码的Full-stack(全栈)应用程序框架,和控制翻转容器的实现。Spring框架的一些核心功能理论,可以用于所有Java应用,Spring还为Java EE构建的Web应用提供大量的扩展支持。Spring框架没有实现任何的编程模型&a…

基于脉冲神经网络的物体检测

访问【WRITE-BUG数字空间】_[内附完整源码和文档] 研究的意义在于探索脉冲神经网络在目标检测上的应用,目前主流的脉冲神经网络训练算法有直接BP训练、STDP无监督训练和训练好的ANN的转化,虽然训练算法众多,但是SNN仍然没有一套成熟的训练算…

Apache Pulsar部署搭建

1.部署规划 部署 Pulsar 集群包括以下步骤(按顺序): 1.部署一个 ZooKeeper 集群,初始化 Pulsar 集群元数据。2.部署一个 Bookeeper 集群。3.部署一个或多个 Pulsar brokers。4.部署 Pulsar manager(可选)。 2.节点规划 主机名…

AIGC技术研究与应用 ---- 下一代人工智能:新范式!新生产力!(1-简介)

文章大纲 AI GC简介决策式/分析式AI(Discriminant/Analytical AI)和生成式AI (Generative AI)参考文献与学习路径模型进化券商研报陆奇演讲AI GC 《我,机器人》中所演绎的一样,主角曾与机器人展开了激烈的辩论,面对“机器人能写出交响乐吗?”“机器人能把画布变成美丽…

(一)before initialization of D3D(初始化D3D之前你需要了解的D3D基础知识)

什么是D3D? D3D全称Direct X 3D,即一组API可以用来针对GPU编程,不过他最主要的作用是用来渲染(不过现在也有很多其他应用比如d3d11va[Direct X 3D 11 Video API]用来进行硬件加速解码) Tips:Direct X 3D主要用来渲染,既然我们说到可以针对GPU编程了,当然不只是渲染的工作可以…