【Go】剑指offer:二叉树子树的判断
时间:2022-07-22
本文章向大家介绍【Go】剑指offer:二叉树子树的判断,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
作者 | 陌无崖
转载请联系授权
题目要求
判断A,B两个二叉树,B是否是A的子树
题目分析
对于这个题,首先我们需要知道二叉树的创建,二叉树的种类有很多,这一题中我们先回顾一下二叉树的基本知识,以二叉查找树为例。
二叉树
二叉树是一种存储数据的结构,有一个根节点,每个结点都有左右指针,指向一个新的结点,称根节点的子节点,而子节点也可以有子节点的树状结构。
二叉查找树
性质
- 任意结点倘若它的左子树不为空,则左子树上的所有结点的值均小于它的根节点的值。
- 任意结点倘若它的右子树不为空,则右子树上的所有结点的值均大于它的根节点的值。
二叉查找树的创建 基于上述的性质,我们可以动态的创建一个查找树。步骤如下:
- 传入一个新结点到一颗二叉树。
- 如果该二叉树的根节点为空,则将此结点置为根节点。
- 如果二叉树根节点不为空,则将此节点将根节点的值进行比较。
- 如果结点的值小于根结点,则继续比较该结点的左结点,直到待比较的结点为空。
- 同理,如果结点的值大于根结点,则继续比较该结点的右结点,直到待比较的结点为空。
定义一个结点类
type treeNode struct {
Val int
Left *treeNode
Right *treeNode
}
定义一个二叉树的类
// 定义一个二叉树类
type binaryTree struct {
// 根结点
root *treeNode
创建
func (t *binaryTree) CreateTree(val int) {
if t.Root() == nil {
t.SetRoot(treeNode{
Val: val,
Left: nil,
Right: nil,
})
} else {
root := t.Root()
for root != nil {
if val <= root.Val && root.Left == nil{
root.Left = &treeNode{val,nil,nil}
break
} else if val > root.Val && root.Right == nil {
root.Right = &treeNode{val,nil,nil}
break
} else if val <= root.Val && root.Left != nil {
root = root.Left
} else if val > root.Val && root.Right != nil {
root = root.Right
}
}
}
}
接着我们回到题目分析的思路上,对于判断B树是否是A树的子树,首先应该判断B树的根节点是否存在于A树中,如果存在,则继续判断B树的左右子树,是否和找到的A树中相同根节点的左右子树相同。这是一个基本的思路,接着我们具体看一下步骤:
- 首先从A树的根节点开始遍历,如果根节点相同,则比较B树的左右结点和A树根结点的左右结点
- 如果不相同,则遍历A树的左右结点进行比较
代码
func HasSubtree(pRoot1 *treeNode, pRoot2 *treeNode) bool {
result := false
if pRoot1 != nil && pRoot2 != nil {
//找到可以开始比较的根节点
if pRoot1.Val == pRoot2.Val {
// 进行比较
result = DoesTreeHHaveTree2(pRoot1, pRoot2)
}
// 开始遍历左节点
if !result {
result = HasSubtree(pRoot1.Left, pRoot2)
}
// 开始遍历右结点
if !result {
result = HasSubtree(pRoot1.Right, pRoot2)
}
}
return result
}
func DoesTreeHHaveTree2(pRoot1 *treeNode, pRoot2 *treeNode) bool {
if pRoot2 == nil {
return true
}
if pRoot1 == nil {
return false
}
if pRoot1.Val != pRoot2.Val {
return false
}
// 不断的递归左右结点进行比较
return DoesTreeHHaveTree2(pRoot1.Left, pRoot2.Left) && DoesTreeHHaveTree2(pRoot1.Right, pRoot2.Right)
}
- Uva----------(11078)Open Credit System
- 学习HTML5之塔克大战(详细记录)
- 学习HTML5之新特性标签一览(详细)
- poj----(1251)Jungle Roads(最小生成树)
- poj-------(2240)Arbitrage(最短路)
- MySQL在线DDL修改表结构的简单经验分享
- HDUOJ-----(1162)Eddy's picture(最小生成树)
- hduoj----1142A Walk Through the Forest(记忆化搜索+最短路)
- java设计之简单的JAVA计算器
- Java之线程———GUI线程(包含打字游戏和计时器俩个GUI实列)
- la----3695 City Game(最大子矩阵)
- poj------(3468)A Simple Problem with Integers(区间更新)
- hdu-------(1698)Just a Hook(线段树区间更新)
- NBitcoin:密码学第2部分
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android:Chip、ChipGroups、ChipDrawable
- Android9.0 使用 AndroidVideoCache 时不能缓存/播放视频的解决
- Android:流式布局实现总结
- 跨域问题汇总
- 优化 Docker 镜像大小常见方法
- 第10期:选择合适的表空间
- 在 Kubernetes 上编排 MongoDB 集群
- k8s技术圈一周精选[第7期]
- TypeScript namespace 命名空间
- 从Pytorch 的ONNX到OpenVINO中IR中间层
- Linux CPU 性能优化指南
- 差分隐私(Differential Privacy)
- ubuntu changelog/source获取方法
- element ui 图片上传封装多张或单张
- Android:友盟分享升级问题总结