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 deque

class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def arr2tree(arr, index):
    # 满二叉树数组格式构造二叉树
    # 构造arr[index]的二叉树
    # 满二叉树数组格式: 依照满二叉树的结构,无论是否为空都会将数组填上
    if index >= len(arr) or arr[index] == None:
        return None
    root = TreeNode(val = arr[index])
    left = arr2tree(arr, 2 * index + 1)
    right = arr2tree(arr, 2 * index + 2)
    root.left = left
    root.right = right
    return root


def 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 -= 1
        result.append(list(path))
        sign = not sign
    return result

if __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 = val
        self.left = left
        self.right = right

def arr2tree(arr, index):
    # 满二叉树数组格式构造二叉树
    # 构造arr[index]的二叉树
    # 满二叉树数组格式: 是指首先按层序遍历顺序,且二叉树的非空节点的左右孩子(尽管为空)都会打印出来,空节点的左右孩子则不打印
    if index >= len(arr) or arr[index] == None:
        return None
    root = TreeNode(val = arr[index])
    left = arr2tree(arr, 2 * index + 1)
    right = arr2tree(arr, 2 * index + 2)
    root.left = left
    root.right = right
    return root

def 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 result

if __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.mfbz.cn/a/369366.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【C++】笔试训练(八)

目录 一、选择题二、编程题1、两种排序方法2、求最小公倍数 一、选择题 1、关于重载函数,哪个说明是正确的() A 函数名相同,参数类型或个数不同 B 函数名相同,返回值类型不同 C 函数名相同,函数内部实现不…

第十二篇【传奇开心果系列】Python的OpenCV技术点案例示例:视频流处理

传奇开心果短博文系列 系列短博文目录Python的OpenCV技术点案例示例短博文系列短博文目录一、前言二、视频流处理介绍三、实时视频流处理示例代码四、视频流分析示例代码五、归纳总结系列短博文目录 Python的OpenCV技术点案例示例短博文系列 短博文目录 一、前言 OpenCV视频…

机器学习_无监督学习之聚类

文章目录 介绍机器学习下的分类K均值算法K值的选取:手肘法用聚类辅助理解营销数据贴近项目实战 介绍机器学习下的分类 以下介绍无监督学习之聚类 聚类是最常见的无监督学习算法。人有归纳和总结的能力,机器也有。聚类就是让机器把数据集中的样本按照特征的性质分组&…

消息队列-RabbitMQ

消息队列-RabbitMQ 中间件 中间件就是帮助连接多个系统,能让多个系统紧密协作的技术或者组件。比如:redis、消息队列。 比如在分布式系统中,将整个系统按业务进行拆分。分成不同的子系统,系统A负责往 redis 存数据,…

ReactNative实现一个圆环进度条

我们直接看效果,如下图 我们在直接上代码 /*** 圆形进度条*/ import React, {useState, useEffect} from react; import Svg, {Circle,G,LinearGradient,Stop,Defs,Text, } from react-native-svg; import {View, StyleSheet} from react-native;// 渐变色 const CircleProgr…

Android学习之路(29) Gradle初探

前言: 大家回想一下自己第一次接触Gradle是什么时候? 相信大家也都是和我一样,在我们打开第一个AS项目的时候, 发现有很多带gradle字样的文件:setting.gradle, build.gradle,gradle.warpper,以及在gradle文件中各种配置&#xff…

基于LLM的文档搜索引擎开发【Ray+LangChain】

Ray 是一个非常强大的 ML 编排框架,但强大的功能伴随着大量的文档。 事实上120兆字节。 我们如何才能使该文档更易于访问? 答案:使其可搜索! 过去,创建自己的高质量搜索结果很困难。 但通过使用 LangChain&#xff0c…

Open CASCADE学习|拓扑变换

目录 平移变换 旋转变换 组合变换 通用变换 平移变换 TopoDS_Shape out;gp_Trsf theTransformation;gp_Vec theVectorOfTranslation(0., 0.125 / 2, 0.);theTransformation.SetTranslation(theVectorOfTranslation);BRepBuilderAPI_Transform myBRepTransformation(out, th…

EAK厚膜功率电阻成功在eVTOL大量使用

eVTOL操作的特点是更高的放电曲线,特别是在起飞和着陆期间。 “传统上,电池要么被设计成提供大量能量,要么被设计成高功率,”Cuberg创始人兼首席执行官Richard Wang说。“对于eVTOL电池来说,在能量和功率之间保持良好…

Acwing---826.单链表

单链表 1.题目2.基本思想3.代码实现 1.题目 实现一个单链表,链表初始为空,支持三种操作: 向链表头插入一个数;删除第 k k k 个插入的数后面的数;在第 k k k 个插入的数后插入一个数。现在要对该链表进行 M M M 次…

中科大计网学习记录笔记(五):协议层次和服务模型

前言: 学习视频:中科大郑烇、杨坚全套《计算机网络(自顶向下方法 第7版,James F.Kurose,Keith W.Ross)》课程 该视频是B站非常著名的计网学习视频,但相信很多朋友和我一样在听完前面的部分发现信…

如何计算两个指定日期相差几年几月几日

一、题目要求 假定给出两个日期,让你计算两个日期之间相差多少年,多少月,多少天,应该如何操作呢? 本文提供网页、ChatGPT法、VBA法和Python法等四种不同的解法。 二、解决办法 1. 网页计算法 这种方法是利用网站给…

69.请描述Spring MVC的工作流程?描述一下 DispatcherServlet 的工作流程?

69.请描述Spring MVC的工作流程?描述一下 DispatcherServlet 的工作流程? 核心架构的具体流程步骤如下: 首先用户发送请求——>DispatcherServlet,前端控制器收到请求后自己不进行处理,而是委托给其他的解析器进行…

day30 window对象——BOM、定时器setTimeout

目录 JavaScript的组成BOM定时器——延时函数两种定时器对比:执行的次数 JavaScript的组成 ECMAScript: 规定了js基础语法核心知识。比如:变量、分支语句、循环语句、对象等等 Web APIs : DOM 文档对象模型, 定义了一套操作HTML文档的APIBOM…

【Iot】什么是串口?什么是串口通信?串口通信(串口通讯)原理,常见的串口通信方式有哪些?

串口通信原理 1. 串口2. 串口通信4. 波特率与比特率5. 帧格式3. 串口通讯的通讯协议3.1. RS2323.2. RS485 总结 1. 串口 串行接口简称串口,也称串行通信接口或串行通讯接口(通常指COM接口),是采用串行通信方式的扩展接口。 串口可…

CICD注册和使用gitlab-runner常见问题

1、现象 fatal: unable to access https://github.com/homebrew/brew/: 2、解决 git config --global --unset http.proxy git config --global --unset https.proxy 查看gitlab-runner是否成功: userusers-MacBook-Pro ~ % gitlab-runner -h 查看gitlab-run…

Vue.js设计与实现(霍春阳)

Vue.js设计与实现 (霍春阳) 电子版获取链接:Vue.js设计与实现(霍春阳) 编辑推荐 适读人群 :1.对Vue.js 2/3具有上手经验,且希望进一步理解Vue.js框架设计原理的开发人员; 2.没有使用过Vue.js,但对Vue.js框架设计感兴趣…

Loki使用指南

转载至我的博客 https://www.infrastack.cn ,公众号:架构成长指南 与其他日志系统相比, Loki 的使用方式是有一定差异性的,需要用不同的思维方式。本文分享一下这些差异以及我们应该如何使用 作为 Loki 用户或操作人员&#xff0…

Leetcode—37. 解数独【困难】

2024每日刷题&#xff08;111&#xff09; Leetcode—37. 解数独 实现代码 class Solution { public:bool isValid(vector<vector<char>>& board, int row, int col, char c) {for(int i 0; i < 9; i) {if(board[row][i] c || board[i][col] c || boar…

最新GPT4.0使用教程,AI绘画,GPT语音对话使用,DALL-E3文生图

一、前言 ChatGPT3.5、GPT4.0、GPT语音对话、Midjourney绘画&#xff0c;文档对话总结DALL-E3文生图&#xff0c;相信对大家应该不感到陌生吧&#xff1f;简单来说&#xff0c;GPT-4技术比之前的GPT-3.5相对来说更加智能&#xff0c;会根据用户的要求生成多种内容甚至也可以和…
最新文章