python_ACM模式《剑指offer刷题》二叉树1

题目:

面试tips:

1. 询问是否可以使用双端队列 (看后面思路就可知为什么要问这个)

思路:

时复和空复都为O(n)

思路一:利用双端队列。总体思想是利用二叉树层序遍历(二叉树的层序遍历就是用队列dq,且从左往右每一层存入队列中),但这里的双端队列使用在path中,即存储路径path时,遇到奇数列,从dq中读出来的节点进行尾插入path;遇到偶数列,从dq中读出来的节点进行头插入。

例如:层序遍历对上述二叉树(因为是层序遍历,因此都是从左往右读取的)

第一层读取: 1 。 因为是奇数层,则存入path尾插,则[1]

第二层读取:2 3 。因为是偶数层,则存入path头插,则[3 2](注意先读取先插)

第三层读取:4 5 6 7 。因为是奇数层,则存入path尾插,则[4 5 6 7](注意先读取先插)

第二层读取:8 9 10 11 12 13 14 15 。因为是偶数层,则存入path头插,则[15 14 13 12 11 10 9 8]

        其实本质上思路一是伪Z字形遍历,因为其在第一次pop节点时还是层序的,只是加入路径path时对奇偶列的加入一个是尾插一个是头插。是leetcode上提供的思路。

        而思路二当在pop节点时就已经时Z字形遍历了。是剑指offer提供的思路。

思路二:利用两个栈。分别称为当前栈,下一栈。分析:若当前栈存储的是奇数行的节点时,则处理时将其左右孩子按顺序存入下一栈中(这样下一次就可以输出右左孩子);若当前栈存储的是偶数行的节点时,则处理时将其右左孩子按顺序存入下一栈(这样下一次就可以输出左右孩子)。

具体分析:

当前栈:第一行。-> 弹出节点1,将其左右孩子存入下一栈23。当前栈为空了则将下一栈作为当前栈,当前栈作为下一栈。result[1]

当前栈:此时节点为23,是第二行。->弹出节点3,将其右左孩子存入下一栈76,弹出节点2,将其右左孩子存入下一栈54,则下一栈为7654。当前栈为空了则将下一栈作为当前栈,当前栈作为下一栈。result[32]

当前栈:result[4567]

````直至两个栈都为空。

代码实现:

思路一:

from collections import dequeclass TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightdef arr2tree(arr, index):# 满二叉树数组格式构造二叉树# 构造arr[index]的二叉树# 满二叉树数组格式: 依照满二叉树的结构,无论是否为空都会将数组填上if index >= len(arr) or arr[index] == None:return Noneroot = TreeNode(val = arr[index])left = arr2tree(arr, 2 * index + 1)right = arr2tree(arr, 2 * index + 2)root.left = leftroot.right = rightreturn rootdef zigzagLevelOrder(root):# 使用双端队列。if not root:return []dq = deque([root])  # 这个作用只是层序遍历的迭代法result = []sign = True  # 表明当前是奇数行while dq:size = len(dq)path = deque()  # 这里使用双端队列while size:# 之所以说其是伪Z字形遍历 就是其取出来时还是层序遍历的从左往右,只是对结果集根据奇数列or偶数列头插或尾插node = dq.popleft()if sign:path.append(node.val)else:path.appendleft(node.val)# 下面都是层序遍历的套路 左右孩子往dq中存if node.left:dq.append(node.left)if node.right:dq.append(node.right)size -= 1result.append(list(path))sign = not signreturn resultif __name__ == '__main__':arr = [3, 9, 20, None, None, 15, 7]root = arr2tree(arr, 0)print(zigzagLevelOrder(root))# [[3], [20, 9], [15, 7]]


思路二:

class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightdef arr2tree(arr, index):# 满二叉树数组格式构造二叉树# 构造arr[index]的二叉树# 满二叉树数组格式: 是指首先按层序遍历顺序,且二叉树的非空节点的左右孩子(尽管为空)都会打印出来,空节点的左右孩子则不打印if index >= len(arr) or arr[index] == None:return Noneroot = TreeNode(val = arr[index])left = arr2tree(arr, 2 * index + 1)right = arr2tree(arr, 2 * index + 2)root.left = leftroot.right = rightreturn rootdef zigzagLevelOrder(root) :# 利用两个栈解决本题# 将奇数层1放入第一个栈中,且放左右孩子在第二个栈中(则下一次就可逆序打印)# 偶数层0时(第二个栈)放右左孩子if not root:return []# 定义一个二维数组 分别是两个栈stack = [[],[]]result = []path = []# 初始化奇数层、偶数层current, next_lay = 1, 0    # 先处理第一层 故当前层是奇数层stack[current].append(root)while stack[current] or stack[next_lay]:# 只要奇数层or偶数层还有节点 说明未遍历完毕node = stack[current].pop()path.append(node.val)if current:# 如果是奇数层则先放左孩子再放右孩子(因为下一层要逆序)if node.left:stack[next_lay].append(node.left)if node.right:stack[next_lay].append(node.right)else:# 若是偶数层则先放右孩子if node.right:stack[next_lay].append(node.right)if node.left:stack[next_lay].append(node.left)if not stack[current]:# 如果当前层空了则更换当前层result.append(path[:])path = []current = 1 - current  # 当前层从奇数层更换成偶数层,偶数层更换为奇数层next_lay = 1 - next_lay    # 下一层从偶数层更换成奇数层,奇数层更换为偶数层return resultif __name__ == '__main__':arr = [3, 9, 20, None, None, 15, 7]root = arr2tree(arr, 0)print(zigzagLevelOrder(root))# [[3], [20, 9], [15, 7]]

参考资料:

1. 《剑指offer》

2. 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/452187.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

WPF图表库LiveChart异常问题处理-System.ArgumentOutOfRangeException:指定的参数超出了有效值的范围

问题: 在使用liveChart处理一个以时间为X轴的曲线时,遇到一个报错:指定的参数超出了有效值的范围System.ArgumentOutOfRangeException:“Specified argument was out of the range of valid values. Arg_ParamName_Name” 指定的参数超出了有…

电脑如何连接手机热点

随着移动互联网的快速发展,越来越多的人使用手机热点进行上网。有时候,我们需要在电脑上连接手机的热点,以方便工作或娱乐。本文将详细介绍如何将电脑连接到手机热点,帮助您轻松实现电脑上网。 一、为什么电脑需要连接手机热点&am…

人类的本性,逃不开党同伐异

近几年以来,不知道大家有没有感受到,网络上越来越充满戾气。 无论哪个网站,只要打开评论区,充斥在眼前的总是一片乌烟瘴气。 一言不合就「对线」,动不动一顶帽子扣过去,说话前先「站队」「找友军」&#xf…

ffmpeg的使用,安装,抽帧,加水印,截图,生成gif,格式转换,抓屏等

实际使用中总结的关于ffmpeg对视频的处理的记录文档 具体信息: http://ffmpeg.org/download.html 官网下载ffmpeg 关于ffmpeg的安装详细步骤和说明 装ffmpeg 方式,Linux和windows下的 http://bbs.csdn.net/topics/390519382 php 调用ffmpeg , http://bbs.csdn.net/t…

动画渲染案例 | 《舒克贝塔·五角飞碟》欢乐开年,经典IP唤醒童年回忆

《舒克贝塔五角飞碟》是由杭州童话大王影视有限公司、天津猫眼微影文化传媒有限公司出品,郑亚旗执导和编剧的动画电影。蓝海创意云为该片提供了渲染服务。电影于2023年12月30日正式上映,上映不到一个月时间累计票房突破5000万大关,并被评为“…

3 编辑器(Vim)

1.完成 vimtutor。备注:它在一个 80x24(80 列,24 行) 终端窗口看起来效果最好。 2.下载我们提供的 vimrc,然后把它保存到 ~/.vimrc。 通读这个注释详细的文件 (用 Vim!), 然后观察 …

Unity引擎学习笔记之【动画剪辑和曲线操作】

动画剪辑和曲线Animation Clip 点选一个包含动画的FBX模型,在其检查器中便可查看动画剪辑 一、动画剪辑 1.Model 2.RIg 538.jpg%20%3D600x&pos_idimg-st6QJc3x-1707050419493) 无动画、旧版Animation动画、普通道具或角色动画、人形角色动画 3.Animation 二…

Unity DOTS中的baking(三)过滤baking的输出

Unity DOTS中的baking(三)过滤baking的输出 默认情况下,在conversation world(baker和baking system运行的环境)下产生的所有entities和components,都会作为baking环节的输出。在baking结束时,U…

【SpringBoot】权限系统与RBAC模型

📝个页人主:五敷有你 🔥系列专栏:SpringBoot⛺️稳重求进,晒太阳 权限系统与RBAC模型 权限 为了解决用户和资源的操作关系, 让指定的用户,只能操作指定的资源。 权限功能 菜单权限&a…

【Java 数据结构】优先级队列(堆)

优先级队列(堆) 1. 优先级队列1.1 概念 2. 优先级队列的模拟实现2.1 堆的概念2.2 堆的存储方式2.3 堆的创建2.3.1 堆向下调整2.3.2 堆的创建2.3.3 建堆的时间复杂度 2.4 堆的插入与删除2.4.1 堆的插入2.4.2 堆的删除 2.5 用堆模拟实现优先级队列 3.常用…

JavaWeb01-JDBC、Druid连接池

目录 一、JDBC 1.概述 2.本质 3.好处 4.使用步骤 5.JDBC_API (1)DriverManager(驱动管理类) (2)Connection(数据库连接对象) (3)Statement &#xf…

Python爬虫urllib详解

前言 学习爬虫,最初的操作便是模拟浏览器向服务器发出请求,那么我们需要从哪个地方做起呢?请求需要我们自己来构造吗?需要关心请求这个数据结构的实现吗?需要了解 HTTP、TCP、IP 层的网络传输通信吗?需要知…