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

news2024/11/23 21:37:06

题目:

面试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.coloradmin.cn/o/1431887.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java高级开发 章节练习题(选择、填空、判断)

第九章 常用实用类 一. 单选题 1. (单选题)String类的equals方法,其作用是: A. 比较2个字符串对象是否为同一个对象B. 比较2个字符串对象的字符长度是否相同C. 比较2个字符串对象的首地址是否相同D. 比较2个字符串对象的字符序列是否相同 答案: D:比…

HBase 数据导入导出

HBase 数据导入导出 1. 使用 Docker 部署 HBase2. HBase 命令查找3. 命令行操作 HBase3.1 HBase shell 命令3.2 查看命名空间3.3 查看命名空间下的表3.4 新建命名空间3.5 查看具体表结构3.6 创建表 4. HBase 数据导出、导入4.1 导出 HBase 中的某个表数据4.2 导入 HBase 中的某…

2V2无人机红蓝对抗仿真

两架红方和蓝方无人机分别从不同位置起飞,蓝方无人机跟踪及击毁红方无人机 2020a可正常运行 2V2无人机红蓝对抗仿真资源-CSDN文库

css1字体属性

一.font-family(字体系列) 不同字体系统用,隔开; 多个字母的字体系统用“”; 二.font-size(字体大小)(有单位px)(默认字体16px) 三.font-weight&#xff08…

大数据信用报告在线查询平台哪个好?

随着大数据技术在金融风控的运用,大数据信用越来越被人熟知,由于线下没有查询大数据信用的地方,想要查询大数据信用报告只有在线上查询,那大数据信用报告在线查询平台哪个好呢?本文贷你一起去了解市面上比较好的三个平台。 大数据…

Unity 渲染管线自动转换的实现 支持HDRP转URP,URP转HDRP

HDRP和URP无法平滑切换,因为属性、功能差异巨大。 本脚本仅对可对应的默认脚本和属性做了转换处理。细节调整还需自己搞。 自动转换可以节省手动更换shader、texture、通用属性的劳动成本。 操作步骤 使用前确保当前项目中存在HDRP和URP的包,没有请到p…

Vue.js 学习14 集成H265web.js播放器实现webpack自动化构建

Vue.js 学习14 集成H265web.js播放器实现webpack自动化构建 一、项目说明1. H265web.js 简介2. 准备环境 二、项目配置1. 下载 H265web.js2. 在vue项目里引入 H265web3. 设置 vue.config.js 三、代码引用1. 参照官方demo , 创建 executor.js2. 在 vue 页面里引用htm…

批量检测微信小程序是否封禁接口源码

<?php // 要检测的 appid 列表 $appids array(appid1, appid2, appid3); // 使用实际的 appid // 循环调用接口检测小程序状态 foreach ($appids as $appid) { $url https://yan.changxunwangluo.cn/xcx/check_mini_program.php?appid . urlencode($appid); $…

【已解决】c++ qt选中该行为什么该列部分变色

笔者开启了QTableView中交替行改变颜色&#xff0c;发现笔者自定义绘制的水平滚动条&#xff0c;在选中后不发生颜色改变&#xff0c;这让笔者很疑惑。笔者查阅资料后发现&#xff0c;自定义绘制的控件&#xff0c;要自身设置颜色。当笔者解决了这个问题时&#xff0c;顺手就将…

GPT原始论文:Improving Language Understanding by Generative Pre-Training论文翻译

1 摘要 自然语理解包括文本蕴含、问题回答、语义相似性评估和文档分类等一系列多样化的任务。尽管大量未标注的文本语料库很丰富&#xff0c;但用于学习这些特定任务的标注数据却很稀缺&#xff0c;这使得基于区分性训练的模型难以充分发挥作用。我们展示了通过在多样化的未标…

高级Java开发工程师岗位的基本职责(合集)

高级Java开发工程师岗位的基本职责1 职责&#xff1a; 1、负责区块链产品的研发&#xff0c;独立或与团队合作&#xff0c;按时保质完成软件开发项目; 2、参与产品系统设计、概要设计工作&#xff0c;核心功能的代码编写; 3、独立解决和指导其他同事处理开发中遇到的难点问题; …

GaussDB新体验,新零售选品升级注入新思路【华为云GaussDB:与数据库同行的日子】

选品思维&#xff1a;低频VS高频 一个的商超&#xff0c;假设有50个左右的品类&#xff0c;每个品类下有2到10个不等的商品。然而如此庞大的商品&#xff0c;并非所有都是高频消费品。 结合自身日常的消费习惯&#xff0c;对于高频和低频的区分并不难。一般大型家电、高端礼盒…

14.2 Java正则表达式(❤❤)

14.2 Java正则表达式 1. 正则表达式1.1 简介1.2 字符范围匹配1.3 元字符1.4 多次重复匹配1.5 定位匹配1.6 贪婪模式与非贪婪模式1.7 表达式分组1. 正则表达式 1.1 简介 开源 在线正则表达式测试 1.2 字符范

mapbox 高亮相同特征的要素数据

一、完整代码 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>Highlight features containing similar data</title> <meta name"viewport" content"initial-scale1,maximum-scale1,user-scal…

VUE3+TS使用OpenSeadragon学习之旅,实现多图片切换效果

1.官方网站&#xff1a;OpenSeadragon 2.使用npm下载插件&#xff1a;npm install openseadragon 3.在 index.html文件引入资源 <link rel"stylesheet" href"node_modules/openseadragon/build/openseadragon/openseadragon.css" /><script src…

正点原子--STM32定时器学习笔记(1)

这部分是笔者对基本定时器的理论知识进行学习与总结&#xff01;&#xff0c;主要记录自己在学习过程中遇到的重难点&#xff0c;其他一些基础点就一笔带过了&#xff01; 1. 定时器概述 1.1 软件定时原理 使用纯软件&#xff08;CPU死等&#xff09;的方式实现定时&#xf…

Python之运算符汇总

1.算数运算符 假设 a 10, b 20 2.比较运算符 3.赋值运算符 4.逻辑运算符 逻辑运算的顺序排列:从左往右开始执行 () > not > and > or and or 一真一假 都为真: 取后面的 取前面的 取假的…

sentinel的Context创建流程分析

sentinel入门 功能 限流&#xff1a;通过限制请求速率、并发数或者用户数量来控制系统的流量&#xff0c;防止系统因为流量过大而崩溃或无响应的情况发生。 熔断&#xff1a;在系统出现故障或异常时将故障节点从系统中断开&#xff0c;从而保证系统的可用性。 降级&#xf…

PyTorch 2.2 中文官方教程(十三)

在 C中注册一个分发的运算符 原文&#xff1a;pytorch.org/tutorials/advanced/dispatcher.html 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 分发器是 PyTorch 的一个内部组件&#xff0c;负责确定在调用诸如torch::add这样的函数时实际运行哪些代码。这可能并不简…

元数据驱动的思想

元数据驱动的思想 元数据驱动的思想应该不会陌生&#xff0c;但元数据驱动的实践应该会非常陌生。 因为元数据驱动架构是为了解决高频个性化的复杂业务而诞生的&#xff0c;而这种业务场景只存在2B领域。 有关元数据驱动的架构思想&#xff0c;在这里暂先简单抛几个点。&#…