《剑指offer》-数据结构篇-树

题目

  1. 重建二叉树

  2. 树的子结构

  3. 二叉树的镜像

  4. 从上往下打印二叉树(层序遍历)

  5. 把二叉树打印成多行

  6. 按之字形顺序打印二叉树

  7. 二叉搜索树的第k个结点(中序遍历)

  8. 二叉搜索树的后序遍历序列(后序遍历)

  9. 二叉树中和为某一值的路径

  10. 二叉树的深度

  11. 平衡二叉树

  12. 二叉树的下一个结点

  13. 对称的二叉树

  14. 序列化二叉树

代码实现

重建二叉树

题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

思路:前序遍历的第一个结点是根节点,据此和中序遍历序列可以找到根节点的左子树、右子树包含的结点,返回的结果是树的层序遍历的结果{1,2,3,4,5,6,7,8}。典型题目,注意迭代的pre和tin的取值范围。

class TreeNode:def __init__(self, x):self.val = xself.left = Noneself.right = None
class Solution:# 返回构造的TreeNode根节点def reConstructBinaryTree(self, pre, tin):# write code hereif len(pre)==0:return Noneroot=TreeNode(pre[0])TinIndex=tin.index(pre[0])root.left=self.reConstructBinaryTree(pre[1:TinIndex+1], tin[0:TinIndex])root.right=self.reConstructBinaryTree(pre[TinIndex+1:], tin[TinIndex+1:])return root

树的子结构

题目描述:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路:依次判断A与B的left、right,判断pRoot2是否是pRoot1的子结构。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:def HasSubtree(self, pRoot1, pRoot2):# write code here#这里认为pRoot1和pRoot2都为空时,没法判断子结构结果,认为比较的结果是False#if not pRoot1 and not pRoot2:#    return Trueif not pRoot1 or not pRoot2:return Falsereturn self.is_subtree(pRoot1, pRoot2) or self.HasSubtree(pRoot1.left, pRoot2) or self.HasSubtree(pRoot1.right, pRoot2)def is_subtree(self, A, B):if not B:return Trueif not A or A.val != B.val:return Falsereturn self.is_subtree(A.left,B.left) and self.is_subtree(A.right, B.right)

二叉树的镜像

题目描述:操作给定的二叉树,将其变换为源二叉树的镜像。

思路:二叉树每一层的结点进行左右交换,看得到的二叉树的结点数值是否一致。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:def Mirror(self, root):# write code hereif not root:return None   left, right = root.left, root.rightroot.left = rightroot.right = leftself.Mirror(root.left)self.Mirror(root.right)return root

从上往下打印二叉树(层序遍历)

题目描述:从上往下打印出二叉树的每个节点,同层节点从左至右打印。

思路:从左至右添加每一层的结点。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:# 返回从上到下每个节点值列表def PrintFromTopToBottom(self, root):# write code hereret = [] if root == None:return retbfs = [root]while(bfs):tbfs = []for node in bfs:ret.append(node.val)if node.left:tbfs.append(node.left)if node.right:tbfs.append(node.right)bfs = tbfsreturn ret

把二叉树打印成多行

题目描述:从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

思路:注意和第13题的区别:这里是每一层输出一行(用列表表示)。因而,输出是一个嵌套列表。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:def Print(self, pRoot):if not pRoot:return []nodeStack=[pRoot]result=[]while nodeStack:res = []nextStack=[]for i in nodeStack:res.append(i.val)if i.left:nextStack.append(i.left)if i.right:nextStack.append(i.right)nodeStack=nextStackresult.append(res)return result

按之字形顺序打印二叉树

题目描述:请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

思路:和第5题类似,但是这里需要对列表中的元素的位置序号进行“奇偶判断”。注意:enumerate()结果的序号是从0开始的。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:def Print(self, pRoot):if not pRoot:return []nodeStack=[pRoot]result=[]while nodeStack:res = []nextStack=[]for i in nodeStack:res.append(i.val)if i.left:nextStack.append(i.left)if i.right:nextStack.append(i.right)nodeStack=nextStackresult.append(res)returnResult=[]#上述代码的运行结果是[[z1],[z2],...,[zn]],z1...zn表示对应的每一层的结点的值for i,v in enumerate(result):if i%2==0:returnResult.append(v)else:returnResult.append(v[::-1])return returnResult

二叉搜索树的第k个结点(中序遍历)

题目描述:给定一棵二叉搜索树,请找出其中的第k小的结点。例如,(5,3,7,2,4,6,8)中,按结点数值大小顺序第三小结点的值为4。

思路:利用中序遍历实现。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:# 中序遍历找到第k个结点的数值def KthNode(self, pRoot, k):# write code hereif not pRoot: return Nonestack = []while pRoot or stack:while pRoot:stack.append(pRoot)pRoot = pRoot.leftpRoot = stack.pop()k -= 1if k == 0:return pRootpRoot = pRoot.right

二叉搜索树的后序遍历序列(后序遍历)

题目描述:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

思路:根据二叉搜索树性质:结点值大于结点的左结点的数值,小于结点的右结点的数值来实现。

# -*- coding:utf-8 -*-
class Solution:def VerifySquenceOfBST(self, sequence):# write code hereif len(sequence)==0:return Falseroot = sequence[-1]i = 0for node in sequence[:-1]:if node > root:breaki += 1for node in sequence[i:-1]:if node < root:return Falseleft = Trueif i > 1:left = self.VerifySquenceOfBST(sequence[:i])right = True#i < (len(sequence)-1)以确保是二叉搜索树if (i < (len(sequence)-1))and left:right = self.VerifySquenceOfBST(sequence[i:-1])return left and right

二叉树中和为某一值的路径

题目描述:输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

思路:递归,依据终止条件左结点=右结点=None且对应的根节点值是之前路径的总和中差的最后一项值。在前序、中序和后序遍历中只有前序遍历是最先访问根节点的,而且题中说在返回的list中数组长度大的数组在前,所以应该采用前序遍历的方法。前序遍历先访问左子树时,在每一个节点的根节点按照从左至右的顺序进行访问。将设定的值expectNumber与所经过的路径中除去最后一个节点的值的和进行相减,然后将结果与遍历的最后一个节点的值进行对比,如果相等的话则说明这条路径是我们所想要的,然后记录下来,返回ret。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:# 返回二维列表,内部每个列表表示找到的路径def FindPath(self, root, expectNumber):# write code hereret = []def dfs(root,sum_,tmp):if root:if root.left==None and root.right == None:if root.val == sum_:tmp.append(root.val)ret.append(tmp[:])else:tmp.append(root.val)dfs(root.left,sum_-root.val,tmp[:])dfs(root.right,sum_-root.val,tmp[:])dfs(root,expectNumber,[])return ret

二叉树的深度

题目描述:输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

思路:递归,求得根节点的左子树和右子树的深度,最后再加1。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:def TreeDepth(self, pRoot):# write code hereif pRoot == None:return 0if pRoot.left == None and pRoot.right==None:return 1return max(self.TreeDepth(pRoot.left),self.TreeDepth(pRoot.right))+1

平衡二叉树

题目描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。

思路:平衡二叉树的定义:是一棵空树或它的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是一棵平衡二叉树。根据定义来直接判断。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:def IsBalanced_Solution(self, pRoot):# write code hereif pRoot == None:return Trueif abs(self.TreeDepth(pRoot.left)-self.TreeDepth(pRoot.right)) > 1:return Falsereturn self.IsBalanced_Solution(pRoot.left) 
and self.IsBalanced_Solution(pRoot.right)def TreeDepth(self, pRoot):# write code hereif pRoot == None:return 0nLeft = self.TreeDepth(pRoot.left)nRight = self.TreeDepth(pRoot.right)return max(nLeft+1,nRight+1)#(nLeft+1 if nLeft > nRight else nRight +1)

二叉树的下一个结点

题目描述:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

思路:判断结点是左、右结点,然后按照中序遍历的先左结点,后父结点,最后右结点的顺序遍历下一个结点。

class TreeNode:def __init__(self, x):self.val = xself.left = Noneself.right = None
class Solution:# 返回构造的TreeNode根节点def reConstructBinaryTree(self, pre, tin):# write code hereif len(pre)==0:return Noneroot=TreeNode(pre[0])TinIndex=tin.index(pre[0])root.left=self.reConstructBinaryTree(pre[1:TinIndex+1], tin[0:TinIndex])root.right=self.reConstructBinaryTree(pre[TinIndex+1:], tin[TinIndex+1:])return root

对称的二叉树

题目描述:请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

思路:递归判断。注意和第12题的区别,这里不是生成一个镜像的二叉树,而是判断已有的二叉树是否是对称的。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None        
class Solution:def isSymmetrical(self, pRoot):# write code heredef is_same(p1,p2):if not p1 and not p2:return Trueif (p1 and p2) and p1.val==p2.val:return is_same(p1.left,p2.right) and is_same(p1.right,p2.left)return Falseif not pRoot:return Trueif pRoot.left and not pRoot.right:return Falseif not pRoot.left and pRoot.right:return Falsereturn is_same(pRoot.left,pRoot.right)

序列化二叉树

题目描述:请实现两个函数,分别用来序列化和反序列化二叉树。二叉树的序列化是指:把一棵二叉树按照某种遍历方式的结果以某种格式保存为字符串,从而使得内存中建立起来的二叉树可以持久保存。序列化可以基于先序、中序、后序、层序的二叉树遍历方式来进行修改,序列化的结果是一个字符串,序列化时通过 某种符号表示空节点(#),以!表示一个结点值的结束(value!)。二叉树的反序列化是指:根据某种遍历顺序得到的序列化字符串结果str,重构二叉树。

思路:序列化的过程:按照层序遍历的方式查找空节点,然后由“#”进行替换。反序列化的过程:查找不是“#”的结点值,然后添加,否则是None。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:def __init__(self):self.index = -1def Serialize(self, root):# write code hereif root:return str(root.val) + ' ' +\self.Serialize(root.left) + \self.Serialize(root.right)else:return '# 'def Deserialize(self, s):# write code herel = s.split()self.index += 1if self.index >= len(s): return Noneif l[self.index] != '#':root = TreeNode(int(l[self.index]))root.left = self.Deserialize(s)root.right = self.Deserialize(s)else:return Nonereturn root

结尾

亲爱的读者朋友:感谢您在繁忙中驻足阅读本期内容!您的到来是对我们最大的支持❤️

正如古语所言:"当局者迷,旁观者清"。您独到的见解与客观评价,恰似一盏明灯💡,能帮助我们照亮内容盲区,让未来的创作更加贴近您的需求。

若此文给您带来启发或收获,不妨通过以下方式为彼此搭建一座桥梁: ✨ 点击右上角【点赞】图标,让好内容被更多人看见 ✨ 滑动屏幕【收藏】本篇,便于随时查阅回味 ✨ 在评论区留下您的真知灼见,让我们共同碰撞思维的火花

我始终秉持匠心精神,以键盘为犁铧深耕知识沃土💻,用每一次敲击传递专业价值,不断优化内容呈现形式,力求为您打造沉浸式的阅读盛宴📚。

有任何疑问或建议?评论区就是我们的连心桥!您的每一条留言我都将认真研读,并在24小时内回复解答📝。

愿我们携手同行,在知识的雨林中茁壮成长🌳,共享思想绽放的甘甜果实。下期相遇时,期待看到您智慧的评论与闪亮的点赞身影✨!

万分感谢🙏🙏您的点赞👍👍、收藏⭐🌟、评论💬🗯️、关注❤️💚~


自我介绍:一线互联网大厂资深算法研发(工作6年+),4年以上招聘面试官经验(一二面面试官,面试候选人400+),深谙岗位专业知识、技能雷达图,已累计辅导15+求职者顺利入职大中型互联网公司。熟练掌握大模型、NLP、搜索、推荐、数据挖掘算法和优化,提供面试辅导、专业知识入门到进阶辅导等定制化需求等服务,助力您顺利完成学习和求职之旅(有需要者可私信联系) 

友友们,自己的知乎账号为“快乐星球”,定期更新技术文章,敬请关注!    

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

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

相关文章

系统定时任务扩展开发指南

适用场景当系统内置定时任务类型无法满足业务需求时&#xff0c;开发者可通过本教程快速掌握自定义定时任务的扩展方法。本指南以"定时检测服务"为例&#xff0c;演示完整开发流程。我想添加一个定时任务 ,而这里没有我需要的,我怎么来添加比如我想添加一个定时检测用…

R语言简介(附电子书资料)

概述 R语言是一种专为统计计算和数据分析设计的编程语言&#xff0c;自诞生以来&#xff0c;凭借其强大的统计分析能力和丰富的可视化功能&#xff0c;成为数据科学、统计学、机器学习等领域的重要工具。电子书资料&#xff1a;https://pan.quark.cn/s/23050825f2be 一、核心特…

关于前端的性能优化

性能优化主要涵盖了以下四个方面: (tip:仅代表个人总结,如有不当,还希望看到的大佬多多指示) 减少网络请求:合并文件、使用 CDN、启用缓存。 优化资源加载:代码分割、懒加载、图片压缩。 提升渲染性能:减少重绘回流、防抖节流、使用 Web Worker。 监控和迭代:定期使用工…

用 FFmpeg 把视频输出为图片序列

用 FFmpeg 把视频输出为图片序列 【推荐】输出为PNG图片序列&#xff08;无损&#xff09; mkdir "D:\Downloads\Recording" ffmpeg -i "C:\Users\33589\Videos\1.mp4" "D:\Downloads\Recording\Recording_%05d.png" 参数含义-i输入视频路径&am…

【linux】高可用集群Keepalived

Keepalived简介Keepalived 是一个基于 VRRP&#xff08;虚拟路由冗余协议&#xff09;的高可用解决方案&#xff0c;主要用于实现 Linux 服务器的负载均衡和故障转移。它通过检测服务器状态并自动切换服务&#xff0c;确保系统在单点故障时仍能保持可用性Keeplived安装启用及配…

如何检查服务器数据盘是否挂载成功?

在服务器配置过程中&#xff0c;确保数据盘正确挂载是非常重要的。如果数据盘未挂载成功&#xff0c;您可能无法访问数据盘上的存储空间。以下是检查Linux服务器中数据盘是否挂载成功的详细步骤&#xff0c;以及如何解决挂载问题。1. 检查数据盘是否挂载成功1.1 使用 df -h 查看…

机器学习概述与 KNN 算法详解

机器学习概述与 KNN 算法详解引言在当今数字化时代&#xff0c;机器学习作为人工智能的核心技术&#xff0c;正深刻改变着我们的生活与工作方式。从日常的智能推荐到复杂的医疗诊断&#xff0c;机器学习技术的应用无处不在。本文将从机器学习的基本概念出发&#xff0c;阐述其核…

Java EE前端技术编程脚本语言JavaScript

-CoderOilStation(程序员编程助手科技股份责任有限公司)Java EE前端技术编程脚本语言JavaScript低代码编程技术编写少量的代码规则。JavaScript脚本编程语言具体细节配置方式编程。前端技术过渡web3.0企业数字化。Java Service Page (JSP) JavaEE jdk6.5 发布企业应用版本Java研…

Docker+Kubernetes 实战:数据模型的弹性伸缩与高可用部署方案

在生产环境中,数据模型的部署面临双重挑战:一方面要应对流量波动(如电商大促期间预测接口调用量激增 10 倍),另一方面需保证服务零中断(金融风控模型 downtime 每增加 1 分钟可能导致数十万元损失)。 本文基于实际项目经验,详细讲解如何通过 Docker 容器化与 Kubernet…

vue3【组件封装】头像裁剪 S-avatar.vue

最终效果 技术要点 图片裁剪 安装依赖 vue-cropper npm install vue-croppernext专用于vue3 项目的图片裁剪&#xff0c;详细使用参考官方文档 页面使用 import "vue-cropper/dist/index.css"; import { VueCropper } from "vue-cropper";<vue-crop…

铜金矿数据分组优化系统设计与实现

铜金矿数据分组优化系统设计与实现 1. 项目概述 本项目旨在开发一个Python程序,用于根据给定的四组分组规则,优化包含金吨、干吨和铜单价等信息的Excel数据分组,以最大化总金额。系统需要处理的核心计算是每条数据的铜货值,其公式为:结算铜金吨 铜单价 (价格系数 + 奖…

Python动态规划:从基础到高阶优化的全面指南(3)

七、动态规划性能优化实战7.1 矩阵快速幂优化def matrix_mult(A, B):"""矩阵乘法"""n len(A)m len(B[0])p len(B)C [[0]*m for _ in range(n)]for i in range(n):for k in range(p):if A[i][k]:for j in range(m):C[i][j] A[i][k] * B[k][j…

海外红人营销的下一站:APP出海如何布局虚拟网红与UGC生态?

在全球移动互联网竞争日益激烈的今天&#xff0c;APP出海推广的重心正从传统流量采买和真人KOL合作&#xff0c;逐步向更具未来感的方向演进。虚拟网红、AI生成内容以及用户生成内容的融合&#xff0c;正为海外红人营销注入全新活力。这不仅是技术革新&#xff0c;更是用户行为…

CentOS网卡未被托管解决记录

VMWare挂起关机&#xff0c;又重启后&#xff0c;出现一些很奇怪的问题。 我的几台CentOS的网卡都不见了&#xff0c;显示网卡未被托管 [rootlocalhost ~]# nmcli device status DEVICE TYPE STATE CONNECTION virbr0 bridge 未托管 -- ens33 …

Node.js 中的内置模板path

1. path的作用&#xff1a;path 是 Node.js 中的一个内置模块&#xff0c;用于处理文件和目录路径。它提供了一些工具来处理路径字符串&#xff0c;确保路径操作跨平台兼容&#xff08;Windows 和 Unix 风格的路径分隔符&#xff09;2.path的常用方法path.join()和数组的join方…

重生之我在暑假学习微服务第三天《Docker-上篇》

个人主页&#xff1a;VON文章所属专栏&#xff1a;微服务系列文章链接&#xff1a;重生之我在暑假学习微服务第一天《MybatisPlus-上篇》-CSDN博客重生之我在暑假学习微服务第二天《MybatisPlus-下篇》-CSDN博客时间&#xff1a;每天12点前准时更新 特别声明&#xff1a;本篇文…

【硬件】LT3763中文手册

目录 1.简介 1.1 特点 1.2 简述 1.3 典型原理图 1.4 绝对最大额定值 2.电气特性 3.引脚功能 4.框图 4.1 设计电感电流 4.2 电感选择 4.3 开关MOSFET选择 4.4 输入电容选择 4.5 输出电容选择 4.6 CBOOST电容选择 4.7 INTVCC电容器选择 4.8 Soft-Start 4.9 输出电流…

【计算机科学与应用】基于多域变换的视频水印嵌入算法研究

导读&#xff1a; 为提升视频水印在版权保护中的实际应用效果&#xff0c;本文提出一种基于多域变换的视频水印嵌入算法。该算法结合离散小波变换(Discrete Wavelet Transform, DWT)与离散余弦变换(Discrete Cosine Transformation, DCT)&#xff0c;利用其在时频域分析与能量…

Axios基本使用

介绍 Axios 是一个基于promise网络请求库&#xff0c;作用于node.js和浏览器中 特性 从浏览器创建 XMLHttpRequests从 node.js 创建 http 请求支持 Promise API拦截请求和响应转换请求和响应数据取消请求自动转换JSON数据客户端支持防御XSRF 安装 项目中 npm install axi…

【大模型LLM】梯度累积(Gradient Accumulation)原理详解

梯度累积&#xff08;Gradient Accumulation&#xff09;原理详解 梯度累积是一种在深度学习训练中常用的技术&#xff0c;特别适用于显存有限但希望使用较大批量大小&#xff08;batch size&#xff09;的情况。通过梯度累积&#xff0c;可以在不增加单个批次大小的情况下模拟…