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

python-leetcode 45.二叉树转换为链表

题目:

给定二叉树的根节点root,请将它展开为一个单链表:

展开后的单链表应该使用同样的TreeNode,其中right子指针指向链表中的下一个节点,而左子指针始终为空

展开后的单链表应该与二叉树先序遍历顺序相同


方法一:二叉树的前序遍历 

将二叉树展开为单链表之后,单链表中的节点顺序即为二叉树的前序遍历访问各节点的顺序。因此,可以对二叉树进行前序遍历,获得各节点被访问到的顺序。由于将二叉树展开为链表之后会破坏二叉树的结构,因此在前序遍历结束之后更新每个节点的左右子节点的信息,将二叉树展开为单链表。

通过递归实现前序遍历

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def flatten(self, root):
        """
        :type root: Optional[TreeNode]
        :rtype: None Do not return anything, modify root in-place instead.
        """
        preorderList=[]#创建一个空列表,用于存储二叉树的所有节点
        def preorderTraversal(root):#递归函数,用于对树进行前序遍历
            if root: #前序遍历的顺序是:根 -> 左 -> 右。
                preorderList.append(root)
                preorderTraversal(root.left)
                preorderTraversal(root.right)
        preorderTraversal(root)
        size=len(preorderList)#二叉树的节点总数
        for i in range(1,size): #从第二个节点开始,直到最后一个节点。因为链表的第一个节点已经由根节点 root 来表示
            prev,curr=preorderList[i-1],preorderList[i]#取当前节点 curr 和前一个节点 prev
            prev.left=None#将 prev 节点的左指针设置为 None
            prev.right=curr #将 prev 节点的右指针指向 curr
        

通过迭代的方式实现前序遍历

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def flatten(self, root):
        """
        :type root: Optional[TreeNode]
        :rtype: None Do not return anything, modify root in-place instead.
        """
        preorderList = []  # 初始化一个空列表用于存储二叉树的节点
        stack = []  # 初始化一个空栈用于存储遍历过程中暂时访问的节点
        node = root

        # 前序遍历二叉树
        while node or stack:
            while node:
                preorderList.append(node)  # 将当前节点添加到列表中
                stack.append(node)  # 将当前节点添加到栈中
                node = node.left  # 继续遍历左子树
            node = stack.pop()  # 当左子树遍历结束时,从栈中弹出一个节点,这个节点是待访问的右子节点(即上一个节点的右子树)
            node = node.right  # 继续访问右子树

        # 构建链表(右子树按前序遍历顺序连接)
        size = len(preorderList)
        for i in range(1, size):  # 从第二个节点开始(因为第一个节点已经是链表的头节点)
            prev, curr = preorderList[i - 1], preorderList[i]
            prev.left = None  # 清空左子树
            prev.right = curr  # 将前一个节点的右指针指向当前节点

时间复杂度:O(n),其中 n 是二叉树的节点数。前序遍历的时间复杂度是 O(n),前序遍历之后,需要对每个节点更新左右子节点的信息,时间复杂度也是 O(n)。

空间复杂度:O(n),其中 n 是二叉树的节点数。空间复杂度取决于栈(递归调用栈或者迭代中显性使用的栈)和存储前序遍历结果的列表的大小,栈内的元素个数不会超过 n,前序遍历列表中的元素个数是 n


方法三:寻找前驱节点

前序遍历访问各节点的顺序是根节点、左子树、右子树。如果一个节点的左子节点为空,则该节点不需要进行展开操作。。如果一个节点的左子节点不为空,则该节点的左子树中的最后一个节点被访问之后,该节点的右子节点被访问。该节点的左子树中最后一个被访问的节点是左子树中的最右边的节点,也是该节点的前驱节点。因此,问题转化成寻找当前节点的前驱节点。

对于当前节点,如果其左子节点不为空,则在其左子树中找到最右边的节点,作为前驱节点,,将当前节点的右子节点赋给前驱节点的右子节点,然后将当前节点的左子节点赋给当前节点的右子节点,并将当前节点的左子节点设为空。对当前节点处理结束后,继续处理链表中的下一个节点,直到所有节点都处理结束。

# Definition for a binary tree node.
# class TreeNode(object):
#     def __init__(self, val=0, left=None, right=None):
#         self.val = val
#         self.left = left
#         self.right = right
class Solution(object):
    def flatten(self, root):
        """
        :type root: Optional[TreeNode]
        :rtype: None Do not return anything, modify root in-place instead.
        """
        curr=root
        while curr:
            if curr.left:
                predecessor=nxt=curr.left#用来找到左子树中最右的节点
                while predecessor.right:#找到左子树中的最右节点
                        predecessor=predecessor.right #向右移动,寻找最右边的节点
                predecessor.right=curr.right#找到左子树中的最右节点后,将当前节点的右子树连接到左子树的最右节点上
                curr.left=None     #当前节点的左子树被置为
                curr.right=nxt#将当前节点的右指针指向左子树的根节点
            curr=curr.right #使curr移动到下一个节点(即当前右子树的第一个节点),继续遍历   
        

时间复杂度:O(n)其中 n 是二叉树的节点数。展开为单链表的过程中,需要对每个节点访问一次,在寻找前驱节点的过程中,每个节点最多被额外访问一次

空间复杂度:O(1)

源自力扣官方题解
 

相关文章:

  • 华为MindIE兼容OpenAI接口与兼容vLLM OpenAI接口的区别(华为VLLM)
  • 企业级AI办公落地实践:基于钉钉/飞书的标准产品解决方案
  • 在阿波罗自动驾驶框架中, 全局路径规划用什么算法
  • drupal是否有翻译的功能,只需要提供文本对应的翻译,自动添加一种语言的所有页面,将对应的文本进行替换
  • windows 下 使用Python OpenCV针对 压缩的tiff 图像进行解压缩 并转换成多张jpeg 图像
  • Asp.Net Web API| React.js| EF框架 | SQLite|
  • Excel的两个小问题解决
  • 如何将图片档案信息读取出来?并把档案信息相关性进行关联
  • Spark技术系列(二):深入理解RDD编程模型——从原理到生产实践
  • 使用Apache Lucene构建高效的全文搜索服务
  • Android双屏异显副屏实现PIP效果小窗口同步显示主屏播放画面
  • gcc编译器优化
  • PHP如何与HTML结合使用?
  • ApplicationContextInitializer
  • 编译和链接
  • 中央一号文件里的三维革命:数字孪生如何重构智慧乡村生态?
  • 蓝桥杯 成绩统计
  • PhotoDoodle: Learning Artistic Image Editing from Few-Shot Examples 论文解读
  • 两个桌面图标助手,你喜欢哪一个
  • uniapp vue3实现的一款数字动画调节器件,支持长按、单点操作,提供丝滑的增减动画效果
  • 国家发改委:大部分稳就业稳经济政策将在6月底前落地
  • 高温最强时段来了!北方局地高温有明显极端性
  • 沧州盐碱地“逆天改命”:无用之地变良田,候鸟翔集水草丰美
  • 江苏疾控:下设部门无“病毒研究所”,常荣山非本单位工作人员
  • “80后”北大硕士罗婕履新甘肃宁县县委常委、组织部部长
  • 广西鹿寨一水文站“倒刺扶手”存安全隐患,官方通报处理情况