LeetCode力扣第114题:多种算法实现 将二叉树展开为链表

server/2024/10/19 13:33:26/

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。
会一些的技术:数据分析、算法、SQL、大数据相关、python
欢迎加入社区:码上找工作
作者专栏每日更新:
LeetCode解锁1000题: 打怪升级之旅
python数据分析可视化:企业实战案例
python源码解读
程序员必备的数学知识与应用

题目描述

给定一个二叉树,原地将它展开为一个单链表。例如,给定二叉树:

    1/ \2   5/ \   \
3   4   6

展开后应该变为:

1\2\3\4\5\6

方法一:递归展开

解题步骤

  1. 如果树为空,直接返回。
  2. 递归展开左子树和右子树。
  3. 将左子树插入到右子树的位置。
  4. 将原来的右子树接到当前右子树的末端。
  5. 考虑到展开后没有左子节点,将左子节点设置为None

代码示例

python">class Solution:def flatten(self, root):if not root:returnself.flatten(root.left)self.flatten(root.right)# 左右子树已经被拉平成一条链表left = root.leftright = root.right# 将左子树作为右子树root.left = Noneroot.right = left# 找到当前右子树(原左子树)的末端并连接原右子树p = rootwhile p.right:p = p.rightp.right = right

方法一的改进主要可以从两个方面进行:优化递归效率和空间使用。虽然基本递归方法简单直观,但它可能导致不必要的栈空间消耗,尤其是在处理非常深的树时可能会导致栈溢出。以下是几种改进策略:

改进1: 尾递归优化

虽然Python默认不支持尾递归优化,但我们可以尽可能减少递归中不必要的操作,将必要的操作移至递归调用之前执行,减少递归调用栈的深度。

改进代码示例

python">class Solution:def flatten(self, root):def flattenTree(node):if not node:return None# 如果节点是叶子节点,直接返回if not node.left and not node.right:return node# 递归平展左子树leftTail = flattenTree(node.left)rightTail = flattenTree(node.right)# 将左子树插入到右子树的地方if leftTail:leftTail.right = node.rightnode.right = node.leftnode.left = None# 返回最后的尾部节点return rightTail if rightTail else leftTailflattenTree(root)
改进2: 减少递归深度

尽可能地在每个节点处理完毕后立即释放其左子树的引用,减少Python垃圾回收器的压力,并减少递归深度。

改进代码示例

python">class Solution:def flatten(self, root):# Helper function to perform flatten operationdef flattenNode(node):if not node:return None# Flatten the left and right subtreeleft_last = flattenNode(node.left)right_last = flattenNode(node.right)# If there is a left subtree, weave it into the right subtreeif left_last:left_last.right = node.rightnode.right = node.leftnode.left = None# The rightmost node is needed for linking to the parent node's right subtreereturn right_last if right_last else left_lastflattenNode(root)

方法二:迭代展开

解题步骤

  1. 使用栈来辅助迭代过程。
  2. 每次取出栈顶元素,如果有右子节点先压栈,再压左子节点。
  3. 修改每个节点的右指针指向下一个栈顶元素,左指针设置为None

代码示例

python">class Solution:def flatten(self, root):if not root:returnstack = [root]prev = Nonewhile stack:curr = stack.pop()if prev:prev.right = currprev.left = Noneif curr.right:stack.append(curr.right)if curr.left:stack.append(curr.left)prev = curr

方法三:寻找前驱节点

解题步骤

  1. 对于每个节点,如果左子节点不为空,找到左子树的最右节点(前驱节点)。
  2. 将原右子树接到前驱节点的右边。
  3. 将左子树移到右边,左子树置为空。
  4. 继续处理链表中的下一个节点。

代码示例

python">class Solution:def flatten(self, root):curr = rootwhile curr:if curr.left:pre = curr.leftwhile pre.right:pre = pre.rightpre.right = curr.rightcurr.right = curr.leftcurr.left = Nonecurr = curr.right

算法分析

  • 时间复杂度
    • 递归展开:(O(n)),每个节点访问一次。
    • 迭代展开:(O(n)),每个节点访问一次。
    • 寻找前驱节点:(O(n)),每个节点访问一次。
  • 空间复杂度
    • 递归展开:(O(n)),递归栈的空间。
    • 迭代展开:(O(n)),使用了额外的栈。
    • 寻找前驱节点:(O(1)),原地修改,不需要额外空间。

优劣势对比

  • 递归展开
    • 优点:实现简单直观。
    • 缺点:需要额外的栈空间来处理递归。
  • 迭代展开
    • 优点:避免了递归可能导致的栈溢出。
    • 缺点:需要使用栈来存储节点。
  • 寻找前驱节点
    • 优点:不需要额外空间,空间复杂度最优。
    • 缺点:代码逻辑相对复杂,需要处理更多的指针操作。

应用示例

这种技巧在处理需要将树结构线性化处理的场景非常有用,例如在图形界面开发中,需要按特定顺序访问或显示节点信息,或者在需要频繁查找、更新结点而又不频繁修改树结构的数据库和文件系统中。


http://www.ppmy.cn/server/41409.html

相关文章

安装InternVL

InternVL 官网 interVL 安装 完全删除环境和环境中的所有软件包 conda remove -n env_name --all 安装 克隆此存储库: git clone https://github.com/OpenGVLab/InternVL.git 创建conda虚拟环境并激活: conda create -n inter pytho…

竞赛课第十周(巴什游戏,尼姆博弈)

目录 目的: 实验内容: 第一题 思路: 【参考代码】 【运行结果】 第二题 输入: 输出: 【参考代码】 【运行结果】 目的: 熟悉并掌握公平组合游戏 (1)巴什游戏、尼姆游戏 (2)图游戏…

【Pytorch】7.使用Module模块搭建简易神经网络

什么是Moudel模块 torch.nn中的module是PyTorch中用于构建神经网络模型的基本单元。它包含了各种神经网络层、激活函数、损失函数等,可以通过组合不同的module来构建复杂的神经网络模型。每个module都包含了参数和方法,可以进行前向传播和反向传播等操作…

面试分享——Elasticsearch面试题

目录 1.Elasticsearch数据建模相关问题 1.1问题描述 1.2问题回答 2.Elasticsearch 查询和分析相关问题 2.1问题描述 2.2问题回答 3.Elasticsearch 集成与开发问题 3.1问题描述 3.2问题回答 4.Elasticsearch DSL 相关应用选型等问题 4.1问题描述 4.2问题回答 4.2.1…

【Web】CTFSHOW 七夕杯 题解

目录 web签到 easy_calc easy_cmd web签到 CTF中字符长度限制下的命令执行 rce(7字符5字符4字符)汇总_ctf中字符长度限制下的命令执行 5个字符-CSDN博客7长度限制直接梭了 也可以打临时文件RCE import requestsurl "http://4ae13f1e-8e42-4afa-a6a6-1076acd08211.c…

DataLab-数据分析的Ai辅助工具

添加图片注释,不超过 140 字(可选)DataLab是一个由DataCamp提供的强大在线数据分析平台,它通过AI技术简化了数据处理流程,使得用户无需编程或数据分析的高级技能即可快速获取数据洞察。它支持多种数据源,包…

组件通信总结

组件通信是前端开发中的一个重要概念,它指的是组件之间通过某种方式来传递信息以达到某个目的。以下是对组件通信的总结: 一、组件间通信的分类 父子组件间通信:这是最常见的组件通信场景,主要使用自定义属性(props&…

算法练习第六十天|84. 柱状图中最大的矩形

84. 柱状图中最大的矩形 柱状图中最大的矩形 class Solution {public int largestRectangleArea(int[] heights) {int[] newHeight new int[heights.length 2];System.arraycopy(heights, 0, newHeight, 1, heights.length);newHeight[heights.length1] 0;newHeight[0] 0;…