剑指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个数字.求出这个圈圈里剩下的最后一个数字 ...
随机推荐
- Linux内核:kthread_create(线程)、SLEEP_MILLI_SEC
转自:http://blog.csdn.net/guowenyan001/article/details/39230181 一.代码 #include <linux/module.h> # ...
- 【转】SqlServer将没有log文件的数据库文件附加到服务器中
原文链接: http://www.cnblogs.com/xdotnet/p/attach_sqlserver_database_file_without_log_files.html 原作者删除了原 ...
- SQL Server 2012 新特性
--Concat示例 ,null,'RTM') --Format实例 DECLARE @d DATETIME = GETDATE(); SELECT FORMAT( @d, 'd', 'en-US' ...
- OpenCV2.4.13+VS2013开发环境配置
List1:完成 写在前面:之前电脑很杂乱的装了OpenCV的2个版本,在配置OpenCV和VS2013环境时死活配不好.但是接下来的工作要用到,没有办法,还是得好好做.今天重新装了OpenCV2.4 ...
- 关于WORD文档的读取乱码问题
一直以来都是用File类操作txt文档,今天想尝试能不能打开word文档,无奈,尝试了UTF8,Unicode,Default....等编码方式,打开文件都是乱码,电脑甚至发出警报声. 以下只取一种编 ...
- iTunes使用总结
UDID查询 将设备连接至电脑,打开iTunes至设备摘要页面,鼠标点击"序列号"区域切换显示UDID
- 未能加载文件或程序集“Microsoft.ReportViewer.WinForms 解决办法
异常信息: 未能加载文件或程序集“Microsoft.ReportViewer.WinForms, Version=10.0.0.0, Culture=neutral, PublicKeyToken= ...
- windows系统时间(SYSTEMTIME)
GetSystemTime函数获得当前的UTC时间,GetLocalTime获得当前的本地时间 UTC是协调世界时(Universal Time Coordinated)英文缩写,是由国际无线电咨询委 ...
- SDOI2009
1226: [SDOI2009]学校食堂Dining Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴 ...
- Android 单元测试(junit、mockito、robolectric)
1.运用JUnit4 进行单元测试 首先在工程的 src 文件夹内创建 test 和 test/java 文件夹. 打开工程的 build.gradle(Module:app)文件,添加JUnit4依 ...
