剑指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个数字.求出这个圈圈里剩下的最后一个数字 ...
随机推荐
- Win7 U盘安装Ubuntu16.04 双系统详细教程
Win7 U盘安装Ubuntu16.04 双系统详细教程 安装主要分为以下几步: 一. 下载Ubuntu 16.04镜像软件: 二. 制作U盘启动盘使用ultraISO: 三. 安装Ubuntu系统: ...
- 攻城狮在路上(陆)-- hadoop分布式环境搭建(HA模式)
一.环境说明: 操作系统:Centos6.5 Linux node1 2.6.32-431.el6.x86_64 #1 SMP Fri Nov 22 03:15:09 UTC 2013 x86_64 ...
- PostSharp 4.0注册机实现过程
PostSharp是基于.NET平台设计的比较强调易学易用的AOP框架. 什么是AOP? http://wayfarer.cnblogs.com/articles/241024.html 新版的已失效 ...
- IDEA快捷键+使用小技巧
一 常用快捷键 Alt+回车 导入包,自动修正,当引入的类需要异常捕获的时候 Ctrl+Shift+Space 自动补全代码,"new"字符,还可以引入强制转换的 Ctrl-Alt ...
- 学习微信小程序之css5
文本的装饰(下划线) 文本的位置,缩进
- SQL Server中的Merge关键字
本文转载地址:http://www.cnblogs.com/CareySon/archive/2012/03/07/2383690.html 简介 Merge关键字是一个神奇的DML关键字.它在SQL ...
- Ie8+,强制默认使用ie8模式
- 十个免费的web应用安全检测工具
Websites are getting more and more complex everyday and there are almost no static websites being bu ...
- 2016-1-28 图解HTTP(03)
6.2.5 非HTTP/1.1首部字段 不限于RFC2616中定义的47种首部字段,还有Cookie.Set-Cookie和Content-Disposition等在其他RFC中首部字段 ...
- C++ win32线程数上限
hThread = CreateThread( NULL, 0, WorkerFunction, &threadParm, 0, &dwThreadID ); 这样的创建方法 ...
