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

news2024/12/23 0:24:05

题目:

面试tips:

        若面试官无特殊要求直接优先采用思路一递归法(易想);若有特殊要求,例如不想要重复遍历中序序列来寻找根节点,则采取思路二,即将中序遍历存入到哈希表中,实现在中序遍历中取根节点的index是O(1)时间复杂度来取;若要求不采用递归的方式,则采取思路三巧妙的迭代法。

思路:

思路一:直接递归思想

        首先明白前序遍历是中左右,中序遍历是左中右。因此根据前序遍历序列,我们可以将序列中第一个值作为根节点,后遍历中序遍历找到根节点的位置index,则对于中序遍历的index左边A序列就是该根节点的左子树的中序遍历,对于中序遍历的index右边B序列就是该根节点的右子树的中序遍历。根据A序列的长度可以找到对应的在前序遍历中的A前序列,前序遍历中剩余的就是B前序列。根据A前和A又构成了新的前序遍历序列和中序遍历序列作为求左子树,右子树同理。

思路二:

        事先存储好中序遍历节点与index的映射关系入哈希表my_dict中。

        但是其思路与思路一就不同了。思路一在构造左右子树时是变更了前序遍历序列和中序遍历序列的,即左子树(是用左子树的前序遍历序列和左子树的中序遍历序列;右子树同理,依次递归下去)。但是思路二因为事先存储好的是整棵树的中序遍历序列,因此在构造其左右子树时就不能再用左右子树的前中遍历序列了,而是也用整棵树的前中遍历序列,因此这就需要在整棵树的前中遍历序列中找到左右子树所对应的index。

        因为哈希表my_dict存储了中序遍历节点与index的映射关系,也就是通过my_dict,可以找到某棵树(子树)的根节点,也就是找到左右子树在中序遍历中的分界线。因此要确定一个树的左右子树,只需要前序遍历中(这里为什么是前序遍历的,因为只有通过前序遍历才能得到root)root的index,中序遍历的左右边界left的index和right的index(这里因为只要root,就可以通过中序遍历得到在中序中root的index,这样再结合left和right的index,就顺利在原始的中序遍历序列上寻找到对应的左右子树的中序遍历序列的所对应的下标区间了!)这样再结合index所求到左右子树的长度,进而在前序遍历序列中找到左右子树root的index,递归下去。详细看代码。读完这段话再看代码就懂了。

思路三:迭代法

        思路三讲解起来有点复杂。这里讲解的很清晰。. - 力扣(LeetCode)

代码实现:

思路一:

时复最理想的情况下(平衡二叉树)是O(n),空复为O(logn);最不理想的情况下(树退化成只有左孩子的单链表)是O(n^2),空复为O(n)。显然时复主要花费时间在在中序遍历中寻找根节点位置,因此有思路二。

class TreeNode:
    def __init__(self,val,left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
def inorder_Traversal(root):
    # 中序遍历验证结果
    if not root:
        return None
    inorder_Traversal(root.left)
    print(root.val, end= ' ')
    inorder_Traversal(root.right)

class Solution:
    def buildTree(self, preorder, inorder):
        # 前序找出根节点 中序找出左右子树
        # 采用递归 每次根据【前序找出根节点 中序找出左右子树】来划分出前序和中序序列
        # 终止条件
        if not preorder:
            return None
        # 单层递归逻辑
        # --------由前序得到根节点--------
        root = TreeNode(preorder[0])
        # -----由中序+根节点 得到左子树和右子树中序序列 以及 左子树个数(其作用是划分前序序列的左右子树)
        for i in range(len(inorder)):
            if inorder[i] == root.val:
                break
            # 得到此时的i即为根节点在中序的位置
        left_inorder = inorder[:i]
        right_inorder = inorder[i+1:]
        # -------利用左子树个数划分前序序列的左右子树
        m = len(left_inorder)
        left_preorder = preorder[1:m+1]
        right_preorder = preorder[m+1:]
        # ---------递归构造
        root.left = self.buildTree(left_preorder, left_inorder)
        root.right = self.buildTree(right_preorder, right_inorder)
        return root

if __name__ == '__main__':
    preorder = [3,9,20,15,7]
    inorder = [9,3,15,20,7]
    a = Solution()
    root = a.buildTree(preorder, inorder)
    inorder_Traversal(root)

思路二:

时复O(n),空复O(n)(链表空间O(n)+哈希表空间O(n)+递归空间O(h)).

class TreeNode:
    def __init__(self,val,left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
def inorder_Traversal(root):
    # 中序遍历验证结果
    if not root:
        return None
    inorder_Traversal(root.left)
    print(root.val, end= ' ')
    inorder_Traversal(root.right)

class Solution:
    def buildTree(self, preorder, inorder):
        def dfs(root, left, right):
            # 根节点下标由前序给出,左右子树的左右边界需要由中序给出
            # 终止条件
            if left > right:
                return None
            # 单层递归
            node = TreeNode(preorder[root])
            i = my_dict[preorder[root]]
            node.left = dfs(root+1, left, i - 1)
            # root + i - left + 1 == root + i - 1 - left + 1 + 1,其中i - 1 - left + 1为左子树的长度
            node.right = dfs(root + i - left + 1, i + 1, right)
            return node
        my_dict = {}
        for i in range(len(inorder)):
            my_dict[inorder[i]] = i
        return dfs(0, 0, len(preorder)-1)

if __name__ == '__main__':
    preorder = [3,9,20,15,7]
    inorder = [9,3,15,20,7]
    a = Solution()
    root = a.buildTree(preorder, inorder)
    inorder_Traversal(root)

思路三:

时复为O(n),空复为O(n)(链表空间O(n)+stack空间O(h)).

class TreeNode:
    def __init__(self,val,left=None,right=None):
        self.val = val
        self.left = left
        self.right = right
def inorder_Traversal(root):
    # 中序遍历验证结果
    if not root:
        return None
    inorder_Traversal(root.left)
    print(root.val, end= ' ')
    inorder_Traversal(root.right)

class Solution:
    def buildTree(self, preorder, inorder):
        # 利用迭代法
        # 对前序数组从左往右,第一个元素为根节点,
        # 判断接下来的素每个元是左子树(前序中若存在左子树则一定是前一个节点的左孩子)还是右子树(前序中右子树不一定为其的右孩子,需要倒序匹配判断)
        if not preorder:
            return None
        root = TreeNode(preorder[0])
        stack = [root]
        index = 0
        for i in range(1, len(preorder)):
            node = stack[-1]
            next_node = TreeNode(preorder[i])
            if node.val != inorder[index]:
                # 如果与中序不相等,则说明i所对应的是左子树(即栈顶节点的左孩子)
                node.left = next_node
                # 遍历过还得加入栈中
                stack.append(next_node)
            else:
                # 如果与中序相等,则说明i所在的是右子树,那么到底是谁的右孩子呢?此时就需要进一步判断
                # 需要将stack从相等的开始倒序遍历找到最后一个相等的节点,那么i所在的位置就是这个最后一个相等的节点的右孩子
                while stack and stack[-1].val == inorder[index]:
                    # 相等则两个都进行移动
                    node = stack.pop()
                    index += 1
                # 跳出来则说明stack为空或者不相等了--如果是对应的前中序数组则应该不会出现空的情况
                node.right = next_node
                stack.append(node.right)
        return root

if __name__ == '__main__':
    preorder = [3,9,20,15,7]
    inorder = [9,3,15,20,7]
    a = Solution()
    root = a.buildTree(preorder, inorder)
    inorder_Traversal(root)

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

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

相关文章

基于卷积神经网络的图像去噪

目录 背影 卷积神经网络CNN的原理 卷积神经网络CNN的定义 卷积神经网络CNN的神经元 卷积神经网络CNN的激活函数 卷积神经网络CNN的传递函数 基于卷积神经网络的图像去噪 完整代码:基于卷积神经网络的图像去噪.rar资源-CSDN文库 https://download.csdn.net/download/abc9918351…

《隐私计算简易速速上手小册》第2章:关键技术介绍(2024 最新版)

文章目录 2.1 同态加密2.1.1 基础知识2.1.2 主要案例:云计算数据分析2.1.3 拓展案例 1:医疗数据分析2.1.4 拓展案例 2:金融风险评估2.2 安全多方计算(SMC)2.2.1 基础知识2.2.2 主要案例:跨机构金融数据共享2.2.3 拓展案例 1:医疗研究合作2.2.4 拓展案例 2:跨国界数据交…

飞天使-linux操作的一些技巧与知识点7-devops

文章目录 简述devopsCICD 简述devops 让技术团队,运维,测试等团队实现一体式流程自动化 进阶版图 CICD 持续集成, 从编译,测试,发布的完成自动化流程 持续交付,包含持续集成,并且将项目部署…

复旦大学MBA:AIGC时代,科技与商业迸发更绚烂的火花

ChatGPT问世以来,AI技术及应用进入一个全速推进的通道,快速迈入通用大模型时代。从AGI(人工通用智能)到AIGC(AI多模态内容生成),AI正在飞速重塑各个行业、人类生活乃至人类的未来。在商业领域更是给营销场景和营销工具…

Flutter开发进阶之Package

Flutter开发进阶之Package 通常我们在Flutter开发中需要将部分功能与整体项目隔离,一般有两种方案Plugin和Package,Application是作为主体项目,Module是作为原生项目接入Flutter模块。 当独立模块不需要与原生项目通讯只需要Plugin就可以&a…

【数据结构-字符串 五】【字符串转换】字符串转为整数

废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是【字符串转换】,使用【字符串】这个基本的数据结构来实现,这个高频题的站点是:CodeTop,筛选条件为&…

Python Web开发记录 Day3:BootStrap

名人说:莫道桑榆晚,为霞尚满天。——刘禹锡(刘梦得,诗豪) 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 三、BootStrap1、BootStrap-初体验2、BootStrap…

MySQL运维实战(7.2) MySQL复制server_id相关问题

作者:俊达 主库server_id没有设置 主库没有设置server_id Got fatal error 1236 from master when reading data from binary log: Misconfigured master - server_id was not set主库查看server_id mysql> show variables like server_id; ----------------…

抖音数据挖掘软件|视频内容提取

针对用户获取抖音视频的需求,我们开发了一款功能强大的工具,旨在解决用户在获取抖音视频时需要逐个复制链接、下载的繁琐问题。我们希望用户能够通过简单的关键词搜索,实现自动批量抓取视频,并根据需要进行选择性批量下载。因此&a…

2D目标检测正负样本分配集合

一:CenterNet Center point based正负样本分配方式:中心像素分配为当前目标。 如果同类的两个高斯核具有交叠的情况,我们逐元素【像素】的选取最大值。Center point based 正样本分配方式的缺点:如果两个不同的物体完美匹配&…

【前端素材】推荐优质后台管理系统Jampack平台模板(附源码)

一、需求分析 后台管理系统(或称作管理后台、管理系统、后台管理平台)是一种专门用于管理网站、应用程序或系统后台运营的软件系统。它通常由一系列功能模块组成,为管理员提供了管理、监控和控制网站或应用程序的各个方面的工具和界面。以下…

JAVA--网络编程

目录 1. 网络编程概述 1.1 软件架构 1.2 网络基础 2. 网络通信要素 2.1 如何实现网络中的主机互相通信 2.2 通信要素一:IP地址和域名 2.2.1 IP地址 2.2.2 域名 2.3 通信要素二:端口号 2.4 通信要素三:网络通信协议 2. 谈传输层协议…

Nest.js权限管理系统开发(二)连接MySQL、Redis

安装MySQL及相关依赖 下载dmg文件安装 前往MySQL :: Download MySQL Community Server下载最新版本的MySQL。 打开系统设置,拉到最下方可以看到MySQL,打开看到两个绿点表示安装成功,也可以在这里修改MySQL密码。 配置环境变量 打开终端配…

数据治理:概述

数据治理概述 一.数据治理及其目标二.数据治理的不同阶段2.1数据集成阶段2.2数据管理阶段2.3成熟阶段 三.什么是成功的数据治理3.1理想状态3.2现实意义 四.数据治理工程师4.1数据梳理与建模4.2数据标准管理4.3元数据管理4.4主数据管理4.5数据质量管理4.6数据安全治理4.7数据集成…

1.手写IOC实现Bean创建过程

1.创建子模块 2.创建测试类 (service dao) 3.创建两个注解 Bean 创建对象 DI 属性注入 4.创建Bean容器接口ApplicationCOntext,定义方法 5.实现bean 容器接口,根据包规则扫描加载Bean,这是在实现Bean。对于Di来说…

134 Linux 系统编程11 ,readlink命令,文件目录rwx权限差异,目录操作函数

一 readlink 命令 前面知道,如果a.soft是一个软链接,我们使用 cat a.soft,会直接查看这个软链接指向的文件 那么我们就是想看这个软链接是啥,可以使用 readlink a.soft 二 获取工作目录 getcwd函数 获取进程当前工作目录 (卷3,标…

sentinel整合nacos在gateway中实现限流

sentinel整合nacos在gateway中实现限流 一、应用层面完成网关整合nacos和sentinel实现限流 前沿 启动nacos与sentinel的jar的启动,这里不细讲 sentinel官网 https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5 sentinel 下载地址 https://github.com/…

软考40-上午题-【数据库】-关系代数运算2-专门的集合运算

一、专门的集合运算 1、投影 示例: 可以用属性名进行投影,也可以用列的序号进行投影。 2、选择 例题 1、笛卡尔积 2、投影 3、选择 3、连接 第一步都要算:笛卡尔积。 3-1、θ连接 示例: 3-2、等值连接 示例: 3-3、自…

代码随想录day32--动态规划理论基础

什么是动态规划 动态规划简称DP,如果某一问题有很多重叠子问题,使用动态规划是最有效的。 所以动态规划中每一个状态一定是由上一个状态推导出来的,这一点一定要和贪心区别出来,贪心没有状态推导,而是直接从局部直接…

新版Java面试专题视频教程——虚拟机篇②

新版Java面试专题视频教程——虚拟机篇② 3 垃圾收回3.1 简述Java垃圾回收机制?(GC是什么?为什么要GC)3.2 对象什么时候可以被垃圾器回收3.2.1 引用计数法3.2.2 可达性分析算法 3.3 JVM 垃圾回收算法有哪些?——4种3.3…