剑指Offer面试题:17.树的子结构
一、题目:树的子结构
题目:输入两棵二叉树A和B,判断B是不是A的子结构。例如下图中的两棵二叉树,由于A中有一部分子树的结构和B是一样的,因此B是A的子结构。
该二叉树的节点定义如下,这里使用C#语言描述:
public class BinaryTreeNode
{
public int Data { get; set; }
public BinaryTreeNode leftChild { get; set; }
public BinaryTreeNode rightChild { get; set; } public BinaryTreeNode(int data)
{
this.Data = data;
} public BinaryTreeNode(int data, BinaryTreeNode left, BinaryTreeNode right)
{
this.Data = data;
this.leftChild = left;
this.rightChild = right;
}
}
二、解题思路
2.1 核心步骤
要查找树A中是否存在和树B结构一样的子树,我们可以分成两步:
Step1.在树A中找到和B的根结点的值一样的结点R;
Step2.判断树A中以R为根结点的子树是不是包含和树B一样的结构。
很明显,这是一个递归的过程。
2.2 代码实现
public static bool HasSubTree(BinaryTreeNode root1, BinaryTreeNode root2)
{
bool result = false; if (root1 != null && root2 != null)
{
if (root1.Data == root2.Data)
{
result = DoesTree1HasTree2(root1, root2);
}
// 从根节点的左子树开始匹配Tree2
if (!result)
{
result = HasSubTree(root1.leftChild, root2);
}
// 如果左子树没有匹配成功则继续在右子树中继续匹配Tree2
if (!result)
{
result = HasSubTree(root1.rightChild, root2);
}
} return result;
} private static bool DoesTree1HasTree2(BinaryTreeNode root1, BinaryTreeNode root2)
{
if (root2 == null)
{
// 证明Tree2已经遍历结束,匹配成功
return true;
} if (root1 == null)
{
// 证明Tree1已经遍历结束,匹配失败
return false;
} if (root1.Data != root2.Data)
{
return false;
}
// 递归验证左子树和右子树是否包含Tree2
return DoesTree1HasTree2(root1.leftChild, root2.leftChild) && DoesTree1HasTree2(root1.rightChild, root2.rightChild);
}
三、单元测试
为了方便测试,这里封装了一个设置指定根节点的左孩子和右孩子节点的方法:SetSubTreeNode
public void SetSubTreeNode(BinaryTreeNode root, BinaryTreeNode lChild, BinaryTreeNode rChild)
{
if (root == null)
{
return;
} root.leftChild = lChild;
root.rightChild = rChild;
}
3.1 功能测试
// 01.树中结点含有分叉,树B是树A的子结构
// 8 8
// / \ / \
// 8 7 9 2
// / \
// 9 2
// / \
// 4 7
[TestMethod]
public void HasSubTreeTest1()
{
BinaryTreeNode nodeA1 = new BinaryTreeNode();
BinaryTreeNode nodeA2 = new BinaryTreeNode();
BinaryTreeNode nodeA3 = new BinaryTreeNode();
BinaryTreeNode nodeA4 = new BinaryTreeNode();
BinaryTreeNode nodeA5 = new BinaryTreeNode();
BinaryTreeNode nodeA6 = new BinaryTreeNode();
BinaryTreeNode nodeA7 = new BinaryTreeNode(); SetSubTreeNode(nodeA1, nodeA2, nodeA3);
SetSubTreeNode(nodeA2, nodeA4, nodeA5);
SetSubTreeNode(nodeA5, nodeA6, nodeA7); BinaryTreeNode nodeB1 = new BinaryTreeNode();
BinaryTreeNode nodeB2 = new BinaryTreeNode();
BinaryTreeNode nodeB3 = new BinaryTreeNode(); SetSubTreeNode(nodeB1, nodeB2, nodeB3); Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), true);
} // 02.树中结点含有分叉,树B不是树A的子结构
// 8 8
// / \ / \
// 8 7 9 2
// / \
// 9 3
// / \
// 4 7
[TestMethod]
public void HasSubTreeTest2()
{
BinaryTreeNode nodeA1 = new BinaryTreeNode();
BinaryTreeNode nodeA2 = new BinaryTreeNode();
BinaryTreeNode nodeA3 = new BinaryTreeNode();
BinaryTreeNode nodeA4 = new BinaryTreeNode();
BinaryTreeNode nodeA5 = new BinaryTreeNode();
BinaryTreeNode nodeA6 = new BinaryTreeNode();
BinaryTreeNode nodeA7 = new BinaryTreeNode(); SetSubTreeNode(nodeA1, nodeA2, nodeA3);
SetSubTreeNode(nodeA2, nodeA4, nodeA5);
SetSubTreeNode(nodeA5, nodeA6, nodeA7); BinaryTreeNode nodeB1 = new BinaryTreeNode();
BinaryTreeNode nodeB2 = new BinaryTreeNode();
BinaryTreeNode nodeB3 = new BinaryTreeNode(); SetSubTreeNode(nodeB1, nodeB2, nodeB3); Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), false);
}
3.2 特殊输入测试
// 03.树中结点只有左子结点,树B是树A的子结构
// 8 8
// / /
// 8 9
// / /
// 9 2
// /
// 2
// /
//
[TestMethod]
public void HasSubTreeTest3()
{
BinaryTreeNode nodeA1 = new BinaryTreeNode();
BinaryTreeNode nodeA2 = new BinaryTreeNode();
BinaryTreeNode nodeA3 = new BinaryTreeNode();
BinaryTreeNode nodeA4 = new BinaryTreeNode();
BinaryTreeNode nodeA5 = new BinaryTreeNode(); nodeA1.leftChild = nodeA2;
nodeA2.leftChild = nodeA3;
nodeA3.leftChild = nodeA4;
nodeA4.leftChild = nodeA5; BinaryTreeNode nodeB1 = new BinaryTreeNode();
BinaryTreeNode nodeB2 = new BinaryTreeNode();
BinaryTreeNode nodeB3 = new BinaryTreeNode(); nodeB1.leftChild = nodeB2;
nodeB2.leftChild = nodeB3; Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), true);
} // 04.树中结点只有左子结点,树B不是树A的子结构
// 8 8
// / /
// 8 9
// / /
// 9 3
// /
// 2
// /
//
[TestMethod]
public void HasSubTreeTest4()
{
BinaryTreeNode nodeA1 = new BinaryTreeNode();
BinaryTreeNode nodeA2 = new BinaryTreeNode();
BinaryTreeNode nodeA3 = new BinaryTreeNode();
BinaryTreeNode nodeA4 = new BinaryTreeNode();
BinaryTreeNode nodeA5 = new BinaryTreeNode(); nodeA1.leftChild = nodeA2;
nodeA2.leftChild = nodeA3;
nodeA3.leftChild = nodeA4;
nodeA4.leftChild = nodeA5; BinaryTreeNode nodeB1 = new BinaryTreeNode();
BinaryTreeNode nodeB2 = new BinaryTreeNode();
BinaryTreeNode nodeB3 = new BinaryTreeNode(); nodeB1.leftChild = nodeB2;
nodeB2.leftChild = nodeB3; Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), false);
} // 05.树中结点只有右子结点,树B是树A的子结构
// 8 8
// \ \
// 8 9
// \ \
// 9 2
// \
// 2
// \
// 5
[TestMethod]
public void HasSubTreeTest5()
{
BinaryTreeNode nodeA1 = new BinaryTreeNode();
BinaryTreeNode nodeA2 = new BinaryTreeNode();
BinaryTreeNode nodeA3 = new BinaryTreeNode();
BinaryTreeNode nodeA4 = new BinaryTreeNode();
BinaryTreeNode nodeA5 = new BinaryTreeNode(); nodeA1.rightChild = nodeA2;
nodeA2.rightChild = nodeA3;
nodeA3.rightChild = nodeA4;
nodeA4.rightChild = nodeA5; BinaryTreeNode nodeB1 = new BinaryTreeNode();
BinaryTreeNode nodeB2 = new BinaryTreeNode();
BinaryTreeNode nodeB3 = new BinaryTreeNode(); nodeB1.rightChild = nodeB2;
nodeB2.rightChild = nodeB3; Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), true);
} // 06.树中结点只有右子结点,树B不是树A的子结构
// 8 8
// \ \
// 8 9
// \ / \
// 9 3 2
// \
// 2
// \
// 5
[TestMethod]
public void HasSubTreeTest6()
{
BinaryTreeNode nodeA1 = new BinaryTreeNode();
BinaryTreeNode nodeA2 = new BinaryTreeNode();
BinaryTreeNode nodeA3 = new BinaryTreeNode();
BinaryTreeNode nodeA4 = new BinaryTreeNode();
BinaryTreeNode nodeA5 = new BinaryTreeNode(); nodeA1.rightChild = nodeA2;
nodeA2.rightChild = nodeA3;
nodeA3.rightChild = nodeA4;
nodeA4.rightChild = nodeA5; BinaryTreeNode nodeB1 = new BinaryTreeNode();
BinaryTreeNode nodeB2 = new BinaryTreeNode();
BinaryTreeNode nodeB3 = new BinaryTreeNode();
BinaryTreeNode nodeB4 = new BinaryTreeNode(); nodeB1.rightChild = nodeB2;
SetSubTreeNode(nodeB2, nodeB3, nodeB4); Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, nodeB1), false);
} // 07.树A为空树
[TestMethod]
public void HasSubTreeTest7()
{
BinaryTreeNode nodeB1 = new BinaryTreeNode();
BinaryTreeNode nodeB2 = new BinaryTreeNode();
BinaryTreeNode nodeB3 = new BinaryTreeNode();
BinaryTreeNode nodeB4 = new BinaryTreeNode(); nodeB1.rightChild = nodeB2;
SetSubTreeNode(nodeB2, nodeB3, nodeB4); Assert.AreEqual(SubTreeHelper.HasSubTree(null, nodeB1), false);
} // 08.树B为空树
[TestMethod]
public void HasSubTreeTest8()
{
BinaryTreeNode nodeA1 = new BinaryTreeNode();
BinaryTreeNode nodeA2 = new BinaryTreeNode();
BinaryTreeNode nodeA3 = new BinaryTreeNode();
BinaryTreeNode nodeA4 = new BinaryTreeNode();
BinaryTreeNode nodeA5 = new BinaryTreeNode(); nodeA1.rightChild = nodeA2;
nodeA2.rightChild = nodeA3;
nodeA3.rightChild = nodeA4;
nodeA4.rightChild = nodeA5; Assert.AreEqual(SubTreeHelper.HasSubTree(nodeA1, null), false);
} // 09.树A和树B都为空树
[TestMethod]
public void HasSubTreeTest9()
{
Assert.AreEqual(SubTreeHelper.HasSubTree(null, null), false);
}
3.3 测试结果
(1)测试通过情况

(2)代码覆盖率

剑指Offer面试题:17.树的子结构的更多相关文章
- 剑指Offer:面试题18——树的子结构(java实现)
问题描述: 输入两棵二叉树A和B,判断B是不是A的子结构.二叉树结点的定义如下: public class TreeNode { int val = 0; TreeNode left = null; ...
- 剑指Offer - 九度1520 - 树的子结构
剑指Offer - 九度1520 - 树的子结构2013-11-30 22:17 题目描述: 输入两颗二叉树A,B,判断B是不是A的子结构. 输入: 输入可能包含多个测试样例,输入以EOF结束.对于每 ...
- 剑指Offer:面试题17——合并两个排序的链表
题目描述 输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则. 思路1: 分别用p1,p2两个指针扫描两个有序链表,p3指针去构建新链表h3. p1.val & ...
- 【剑指offer 面试题17】合并两个排序的链表
思路: 比较两个链表端点值的大小,通过递归的方式排列. #include <iostream> using namespace std; struct ListNode { int val ...
- 剑指offer面试题17:合并两个排序的链表
题目:输入两个递增排序的链表,合并这两个链表并使新链表中的节点人是按照递增排序的.解题思路:两个链表分别都已经是有序的了,遍历链表的时候只要比较两个链表当前位置大小,取出最小的添加到新链表中. 可以有 ...
- 剑指offer——面试题17:打印从1到最大的n位数
用字符串模拟加法: #include"iostream" #include"string.h" using namespace std; bool AddOne ...
- 【剑指offer】Q18:树的子结构
类似于字符串的匹配,我们总是找到第一个匹配的字符,在继续比較以后的字符是否所有同样,假设匹配串的第一个字符与模式串的第一个不同样,我们就去查看匹配串的下一个字符是否与模式串的第一个同样,相应到这里,就 ...
- C++版 - 剑指Offer 面试题39:二叉树的深度(高度)(二叉树深度优先遍历dfs的应用) 题解
剑指Offer 面试题39:二叉树的深度(高度) 题目:输入一棵二叉树的根结点,求该树的深度.从根结点到叶结点依次经过的结点(含根.叶结点)形成树的一条路径,最长路径的长度为树的深度.例如:输入二叉树 ...
- C++版 - 剑指offer 面试题24:二叉搜索树BST的后序遍历序列(的判断) 题解
剑指offer 面试题24:二叉搜索树的后序遍历序列(的判断) 题目:输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果.如果是则返回true.否则返回false.假设输入的数组的任意两个 ...
- C++版 - 剑指Offer 面试题45:圆圈中最后剩下的数字(约瑟夫环问题,ZOJ 1088:System Overload类似)题解
剑指Offer 面试题45:圆圈中最后剩下的数字(约瑟夫环问题) 原书题目:0, 1, - , n-1 这n个数字排成一个圈圈,从数字0开始每次从圆圏里删除第m个数字.求出这个圈圈里剩下的最后一个数字 ...
随机推荐
- 感知机(perceptron)概念与实现
感知机(perceptron) 模型: 简答的说由输入空间(特征空间)到输出空间的如下函数: \[f(x)=sign(w\cdot x+b)\] 称为感知机,其中,\(w\)和\(b\)表示的是感知机 ...
- Myeclipse下的struts2.3.8 配置 保证绝对好用
转自:http://blog.csdn.net/oxuannishi/article/details/8538386 1.建立web project工程,我的结构如下: 2.这一步非常重要:引入必要的 ...
- HTTPS和HTTP的区别(转)
HTTPS和HTTP的区别 超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信 息.HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器 ...
- OpenCV特征点检测------ORB特征
OpenCV特征点检测------ORB特征 ORB是是ORiented Brief的简称.ORB的描述在下面文章中: Ethan Rublee and Vincent Rabaud and Kurt ...
- Vmware无法获取快照信息 锁定文件失败
今天早上起来发现虚拟机崩了: 造成原因: 如果使用VMWare虚拟机的时候突然系统崩溃蓝屏,有一定几率会导致无法启动, 会提示:锁定文件失败,打不开磁盘或快照所依赖的磁盘: 这是因为虚拟机在运行的时候 ...
- 深入理解Javascript--闭包
原网站http://www.cnblogs.com/xiaoloulan/p/5980569.html 在了解闭包之前需要了解下作用域的工作原理作为基础,传送门. 闭包是一个老生常谈的问题,在面试中也 ...
- WebGL入门教程(四)-webgl颜色
前面文章: WebGL入门教程(一)-初识webgl WebGL入门教程(二)-webgl绘制三角形 WebGL入门教程(三)-webgl动画 颜色效果图: 操作步骤: 1.创建HTML5 canva ...
- WPF menu
MenuMenu的样式很简单,就是顶部的那个框,如下图 而其中的文字“文件”“图形”...是属于MenuItem的,要灵活使用MenuItem,就需要了解MenuItem.Role的作用 TopLev ...
- nginx:文件下载指定保存文件名的配置
一般在我们上传完资源文件之后,为了避免文件名冲突,会将文件名改成毫无意义的一段字符.这个字符,可能是MD5产生的,或者是其他方式产生的字符串.这时候,下载的时候,默认保存的文件名会是这段毫无意义的文件 ...
- iOS 遇到的错误总结
1.[[[NSBundle mainBundle] loadNibNamed:@"UIFeedbackController" owner:nil options:nil] firs ...
