二叉树展开为链表

 Python算法题集_二叉树展开为链表

  • 题114:二叉树展开为链表
  • 1. 示例说明
  • 2. 题目解析
    • - 题意分解
    • - 优化思路
    • - 测量工具
  • 3. 代码展开
    • 1) 标准求解【DFS递归+先序遍历】
    • 2) 改进版一【BFS迭代+先序遍历】
    • 3) 改进版二【DFS递归+直接转换】
    • 4) 改进版三【BFS迭代+直接转换】
  • 4. 最优算法

本文为Python算法题集之一的代码示例

题114:二叉树展开为链表

1. 示例说明

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

    • 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null
    • 展开后的单链表应该与二叉树 先序遍历 顺序相同。

    示例 1:

    二叉树展开为链表_第1张图片

    输入:root = [1,2,5,3,4,null,6]
    输出:[1,null,2,null,3,null,4,null,5,null,6]
    

    示例 2:

    输入:root = []
    输出:[]
    

    示例 3:

    输入:root = [0]
    输出:[0]
    

    提示:

    • 树中结点数在范围 [0, 2000]
    • -100 <= Node.val <= 100

    **进阶:**你可以使用原地算法(O(1) 额外空间)展开这棵树吗?


2. 题目解析

- 题意分解

  1. 先序遍历是一种二叉树遍历方法,也被称为先根遍历或前序遍历;在先序遍历中,首先访问根结点,然后遍历左子树,最后遍历右子树。
  2. 本题有两个计算部分,1为二叉树先序遍历,2是生成链表
  3. 基本的设计思路是深度优先算法【DFS(Depth-First Search)】、广度有限算法【BFS(Breadth-First Search)】

- 优化思路

  1. 通常优化:减少循环层次

  2. 通常优化:增加分支,减少计算集

  3. 通常优化:采用内置算法来提升计算速度

  4. 分析题目特点,分析最优解

    1. 可以考虑使用DFS、BFS进行先序遍历,生成遍历结果,然后再生成链表,这样会得到链表和与其同步的列表数据【检索方便】

    2. 可以不生成遍历结果,直接将二叉树变形为链表,这样就必须将根节点的左子树最右节点的右指针指向根节点的右子树,此方法空间复杂度为0(1)


- 测量工具

  • 本地化测试说明:LeetCode网站测试运行时数据波动很大【可把页面视为功能测试】,因此需要本地化测试解决数据波动问题
  • CheckFuncPerf(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块
  • 本题本地化超时测试用例自己生成,详见【最优算法章节】

3. 代码展开

1) 标准求解【DFS递归+先序遍历】

使用深度优先算法执行先序遍历,然后生成链表

马马虎虎,超过59%二叉树展开为链表_第2张图片

import CheckFuncPerf as cfp

class Solution:
 def flatten_base(self, root):
     def dfspreorder(root, listnode):
         if root is None:
             return []
         listnode.append(root)
         dfspreorder(root.left, listnode)
         dfspreorder(root.right, listnode)
     list_node = []
     dfspreorder(root, list_node)
     for iIdx in range(len(list_node)-1):
         list_node[iIdx].left = None
         list_node[iIdx].right = list_node[iIdx+1]

aSolution = Solution()
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.flatten_base, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result']))

# 运行结果
函数 flatten_base 的运行时间为 271.27 ms;内存使用量为 40.00 KB 执行结果 = None

2) 改进版一【BFS迭代+先序遍历】

使用广度优先算法执行先序遍历,然后生成链表

性能卓越,超越96%二叉树展开为链表_第3张图片

import CheckFuncPerf as cfp

class Solution:
 def flatten_ext1(self, root):
     if root is None:
         return []
     list_node = []
     stack = [root]
     while stack:
         node = stack.pop()
         list_node.append(node)
         if node.right:
             stack.append(node.right)
         if node.left:
             stack.append(node.left)
     for iIdx in range(len(list_node)-1):
         list_node[iIdx].left = None
         list_node[iIdx].right = list_node[iIdx+1]

aSolution = Solution()
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.flatten_ext1, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result']))

# 运行结果
函数 flatten_ext1 的运行时间为 252.33 ms;内存使用量为 756.00 KB 执行结果 = None

3) 改进版二【DFS递归+直接转换】

使用深度优先算法执行遍历,过程中直接将二叉树改为链表

马马虎虎,超过75%在这里插入图片描述

import CheckFuncPerf as cfp

class Solution:
 def flatten_ext2(self, root):
     def dtspreorder(root):
         if root == None:
             return
         dtspreorder(root.left)
         dtspreorder(root.right)
         if root.left != None:
             nextnode = root.left
             while nextnode.right:
                 nextnode = nextnode.right
             nextnode.right = root.right
             root.right = root.left
             root.left = None
     dtspreorder(root)

aSolution = Solution()
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.flatten_ext2, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result']))

# 运行结果
函数 flatten_ext2 的运行时间为 653.25 ms;内存使用量为 0.00 KB 执行结果 = None

4) 改进版三【BFS迭代+直接转换】

使用广度优先算法执行遍历,过程中直接将二叉树改为链表

性能优越,超越91%在这里插入图片描述

import CheckFuncPerf as cfp

class Solution:
 def flatten_ext3(self, root):
     while (root != None):
         if root.left != None:
             nextnode = root.left
             while nextnode.right != None:
                 nextnode = nextnode.right
             nextnode.right = root.right
             root.right = root.left
             root.left = None
         root = root.right

aSolution = Solution()
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.flatten_ext3, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result']))

# 运行结果
函数 flatten_ext3 的运行时间为 162.54 ms;内存使用量为 0.00 KB 执行结果 = None

4. 最优算法

根据本地日志分析,最优算法为第4种方式【BFS迭代+直接转换】flatten_ext3

import random
ilen, imode = 1000000, 1
def generate_binary_tree(node_count, imode):
    if node_count <= 0:
        return None
    root = TreeNode(random.randint(1, 100))
    node_count -= 1
    if imode > 3:
        imode = 1
    if imode == 1:
        left = generate_binary_tree(node_count // 2, imode+1)
        right = generate_binary_tree(node_count // 2, imode+1)
        root.left = left
        root.right = right
    elif imode==2:
        left = generate_binary_tree(node_count, imode+1)
        root.left = left
    else:
        right = generate_binary_tree(node_count, imode+1)
        root.right = right
    return root
aSolution = Solution()
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.flatten_base, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result']))
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.flatten_ext1, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result']))
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.flatten_ext2, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result']))
aroot = generate_binary_tree(ilen, imode)
result = cfp.getTimeMemoryStr(Solution.flatten_ext3, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result']))

# 算法本地速度实测比较
函数 flatten_base 的运行时间为 271.27 ms;内存使用量为 40.00 KB 执行结果 = None
函数 flatten_ext1 的运行时间为 252.33 ms;内存使用量为 756.00 KB 执行结果 = None
函数 flatten_ext2 的运行时间为 653.25 ms;内存使用量为 0.00 KB 执行结果 = None
函数 flatten_ext3 的运行时间为 162.54 ms;内存使用量为 0.00 KB 执行结果 = None

一日练,一日功,一日不练十日空

may the odds be ever in your favor ~

你可能感兴趣的:(Python,链表,leetcode,力扣,python,二叉树)