要求是这样的:给定两颗二叉树A和B,判断B是否是A的子树。
在下面这个例子中可以看到B是A的子树。
想一想该怎样解决这个问题呢?
如果B是A的一颗子树,那么B一定和A的一个颗子树完全一样,因此我们可以实现一个函数isSame来判断两颗二叉树是否完全相同,这个函数非常容易实现:
bool isSame(TreeNode* a, TreeNode* b) { if (a == nullptr && b == nullptr) return true; else if (a == nullptr || b == nullptr) return false; else return a->val == b->val && isSame(a->left, b->left) && isSame(a->right, b->right); }只需要三行代码就能搞定,该函数非常简单:
如果二叉树a和b都为空,那么显然返回true
否则如果a为空或者b为空,那么这两棵树显然不相同,返回false
如果不满足条件1和2,那么如果a和b根节点的值相同并且其左右子树都一样,那么二叉树a和b是相同的二叉树,返回true
有了isSame函数剩下的就简单啦,我们只需要在遍历二叉树a时不断的调用isSame函数判断是否b是a的子树相同:
同样的,只需要三行代码就能搞定:
bool isSubtree(TreeNode* root, TreeNode* subRoot) { if (root == nullptr && subRoot == nullptr) return true; else if (root == nullptr || subRoot == nullptr) return false; else return isSame(root, subRoot) || isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot); }代码非常简单,就是二叉树的普通遍历。
有的同学可能已经发现了,这种算法的实际上不太高效,原因就在于对于二叉树a上的每个节点我们都需要调用一遍isSame函数,如果二叉树a的节点数为M、二叉树b的节点数为N,那么该算法的时间复杂度为O(M*N)。
我们一定对二叉树a中的每个节点都调用一遍isSame函数吗?
实际上这并不是必须的。
要能想出更高效的算法,你需要理解编码的概念。
熟悉md5的同学都知道,我们可以对任何一个文件计算出md5值,md5就是一串数字,就好像指纹一样,只需要两个文件完全一样,那么这两个文件的md5就完全一样,因此我们可以通过比较md5来确认两个文件是否完全一样,在linux下用md5sum命令可以计算一个文件的md5值:
$ md5sum a.c 6004b6a21b274b405a2bd1f1c75a93c7 a.c同样的,我们也可以对二叉树计算“md5”值。
怎么计算呢?
实际上非常简单。
我们只需要在二叉树的前序遍历过程中输出“遍历轨迹”,那么就能将一颗二叉树序列化成一个字符串。
如果二叉树b是a的子树,那么必然二叉树b序列化的后的字符串是a序列化后的字符串的子串。
这样通过编码,我们将二叉树子树的判断问题转化为了字符串的子串匹配问题,而字符串匹配问题可以通过经典的KMP算法解决。
将二叉树序列化为字符串的函数也很简单:
void serialize(TreeNode* root, string& str) { if (root == nullptr) { str = str + "#"; } else { str = str + "," + to_string(root->val); serialize(root->left, str); serialize(root->right, str); } }可以看到,该代码实际上还是二叉树的遍历。
既然我们可以将二叉树序列化了字符串,那么接下来就简单啦:
bool isSubtree(TreeNode* root, TreeNode* subRoot) { string a, b; serialize(root, a); serialize(subRoot, b); return a.find(b)!=string::npos; }将二叉树序列化为字符串后只需要判断字符串b是否是字符串a的子串即可。
从这个题目上我们可以看到信息编码的重要作用,这也是一种非常值得掌握的思想,有时对解决问题有四两拨千斤的效果。
审核编辑:刘清
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。
举报投诉
-
编码器
+关注
关注
45文章
3643浏览量
134510 -
Linux系统
+关注
关注
4文章
593浏览量
27397 -
字符串
+关注
关注
1文章
579浏览量
20513 -
二叉树
+关注
关注
0文章
74浏览量
12324
原文标题:面试官:这么简单的二叉树算法都不会?
文章出处:【微信号:TheAlgorithm,微信公众号:算法与数据结构】欢迎添加关注!文章转载请注明出处。
发布评论请先 登录
相关推荐
二叉树算法在单总线技术中的应用
介绍了单总线技术和二叉树算法。单总线技术可以将地址线、数据线和控制线合成一根线,并允许在这根线上挂接多个单总线器件。提出了用二叉树算法搜索单总线器件注册码,并
发表于 03-16 09:38
•20次下载
基于二叉树分解的自适应防碰撞算法
该文提出了一种基于二叉树分解的自适应防碰撞算法。新算法利用标签EPC 的唯一性,通过时隙分配估计标签的分布情况,对发生碰撞的时隙进行二叉树搜索,从而将一个庞大且复杂
发表于 11-17 14:09
•21次下载
基于二叉树的时序威廉希尔官方网站 测试序列设计
为了实现时序威廉希尔官方网站
状态验证和故障检测,需要事先设计一个输入测试序列。基于二叉树节点和树枝的特性,建立时序威廉希尔官方网站
状态二叉树,按照威廉希尔官方网站
二叉树节点(状态)与树枝(输入)的层次逻辑
发表于 07-12 13:57
•0次下载
二叉树层次遍历算法的验证
实现二叉树的层次遍历算法,并对用”A(B(D,E(H(J,K(L,M(,N))))),C(F,G(,I)))”创建的二叉树进行测试。
发表于 11-28 01:05
•2099次阅读
二叉树操作的相关知识和代码详解
树是数据结构中的重中之重,尤其以各类二叉树为学习的难点。在面试环节中,二叉树也是必考的模块。本文主要讲二叉树操作的相关知识,梳理面试常考的内容。请大家跟随小编一起来复习吧。 本篇针对面
二叉树的前序遍历非递归实现
我们之前说了二叉树基础及二叉的几种遍历方式及练习题,今天我们来看一下二叉树的前序遍历非递归实现。 前序遍历的顺序是, 对于树中的某节点,先遍历该节点,然后再遍历其左子树,最后遍历其右子
C语言数据结构:什么是二叉树?
完全二叉树:完全二叉树是效率很高的数据结构。对于深度为K,有n个节点的二叉树,当且仅当每一个节点都与深度为K的满二叉树中编号从1至n的节点一一对应时,称为完全
怎么就能构造成二叉树呢?
一直跟着公众号学算法的录友 应该知道,我在二叉树:构造二叉树登场!,已经讲过,只有 中序与后序 和 中序和前序 可以确定一颗唯一的二叉树。前序和后序是不能确定唯一的
评论