Python算法题集_翻转二叉树
- 题226:翻转二叉树
- 1. 示例说明
- 2. 题目解析
- - 题意分解
- - 优化思路
- - 测量工具
- 3. 代码展开
- 1) 标准求解【DFS递归】
- 2) 改进版一【BFS迭代,节点循环】
- 3) 改进版二【BFS迭代,列表循环】
- 4. 最优算法
本文为Python算法题集之一的代码示例
题226:翻转二叉树
1. 示例说明
-
示例 1:
输入:root = [4,2,7,1,3,6,9] 输出:[4,7,2,9,6,3,1]
示例 2:
输入:root = [2,1,3] 输出:[2,3,1]
示例 3:
输入:root = [] 输出:[]
提示:
- 树中节点数目范围在
[0, 100]
内 -100 <= Node.val <= 100
- 树中节点数目范围在
2. 题目解析
- 题意分解
- 本题为二叉树的翻转
- 基本的设计思路是深度优先算法【DFS(Depth-First Search)】、广度有限算法【BFS(Breadth-First Search)】
- 优化思路
-
通常优化:减少循环层次
-
通常优化:增加分支,减少计算集
-
通常优化:采用内置算法来提升计算速度
-
分析题目特点,分析最优解
- 可以考虑采用迭代法改写递归函数,提高性能
- 测量工具
- 本地化测试说明:LeetCode网站测试运行时数据波动很大,因此需要本地化测试解决这个问题
CheckFuncPerf
(本地化函数用时和内存占用测试模块)已上传到CSDN,地址:Python算法题集_检测函数用时和内存占用的模块- 本题本地化超时测试用例自己生成,详见【最优算法章节】
3. 代码展开
1) 标准求解【DFS递归】
采用深度优先算法,标准递归实现
马马虎虎,超过66%
import CheckFuncPerf as cfp
class Solution:
def invertTree_base(self, root):
if not root:
return None
root.left, root.right = root.right, root.left
self.invertTree_base(root.left)
self.invertTree_base(root.right)
return root
aroot = generate_binary_tree(ilen)
aSolution = Solution()
result = cfp.getTimeMemoryStr(Solution.invertTree_base, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))
# 运行结果
函数 invertTree_base 的运行时间为 600.12 ms;内存使用量为 4.00 KB 执行结果 = 71
2) 改进版一【BFS迭代,节点循环】
通过堆栈结构的迭代算法来改写递归算法,单次循环一个节点
性能良好,超过82%
import CheckFuncPerf as cfp
class Solution:
def invertTree_ext1(self, root):
if not root:
return None
stacktree = [root]
while stacktree:
tmpnode = stacktree.pop()
tmpnode.left, tmpnode.right = tmpnode.right, tmpnode.left
if tmpnode.right:
stacktree.append(tmpnode.right)
if tmpnode.left:
stacktree.append(tmpnode.left)
return root
aroot = generate_binary_tree(ilen)
aSolution = Solution()
result = cfp.getTimeMemoryStr(Solution.invertTree_ext1, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))
# 运行结果
函数 invertTree_ext1 的运行时间为 546.13 ms;内存使用量为 0.00 KB 执行结果 = 7
3) 改进版二【BFS迭代,列表循环】
通过队列结构的迭代算法来改写递归算法,每次循环一个批次,减少了部分循环判断计算
勉强通关,超过19%
import CheckFuncPerf as cfp
class Solution:
def invertTree_ext2(self, root):
if not root:
return None
queueTree = [root]
while queueTree:
for iIdx in range(len(queueTree)):
tmpnode = queueTree.pop()
tmpnode.left, tmpnode.right = tmpnode.right, tmpnode.left
if tmpnode.left:
queueTree.append(tmpnode.left)
if tmpnode.right:
queueTree.append(tmpnode.right)
return root
aroot = generate_binary_tree(ilen)
aSolution = Solution()
result = cfp.getTimeMemoryStr(Solution.invertTree_ext2, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))
# 运行结果
函数 invertTree_ext2 的运行时间为 471.11 ms;内存使用量为 0.00 KB 执行结果 = 21
4. 最优算法
根据本地日志分析,最优算法为第3种方式【BFS迭代,列表循环】inorderTraversal_ext2
import random
ilen = 1000000
def generate_binary_tree(node_count):
if node_count <= 0:
return None
root = TreeNode(random.randint(1, 100))
left = generate_binary_tree(node_count // 2)
right = generate_binary_tree(node_count // 2)
root.left = left
root.right = right
return root
aroot = generate_binary_tree(ilen)
aSolution = Solution()
result = cfp.getTimeMemoryStr(Solution.invertTree_base, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))
aroot = generate_binary_tree(ilen)
result = cfp.getTimeMemoryStr(Solution.invertTree_ext1, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))
aroot = generate_binary_tree(ilen)
result = cfp.getTimeMemoryStr(Solution.invertTree_ext2, aSolution, aroot)
print(result['msg'], '执行结果 = {}'.format(result['result'].val))
# 算法本地速度实测比较
函数 invertTree_base 的运行时间为 600.12 ms;内存使用量为 4.00 KB 执行结果 = 71
函数 invertTree_ext1 的运行时间为 546.13 ms;内存使用量为 0.00 KB 执行结果 = 7
函数 invertTree_ext2 的运行时间为 471.11 ms;内存使用量为 0.00 KB 执行结果 = 21
一日练,一日功,一日不练十日空
may the odds be ever in your favor ~