剑指offer-17 树的子结构
一、题目描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构
输入:{8,8,#,9,#,2,#,5},{8,9,#,2}
输出:true
母树A: 子树B:
二、解题步骤
1.解题思路
如果树B是树A的子结构,则子树的根节点可能是母树的任意一个节点,因此判定是否是子结构需要进行两步判断:
(1)先序遍历树 A 中的每个节点 n
(2)判断树A中以n为根节点的子树,是否包含树B。
终止条件:
当节点 B 为空:说明树 B 已匹配完成(越过叶子节点),因此返回 true;
当节点 A为空:说明已经越过树 A叶子节点,即匹配失败,返回 false;
当节点 A和 B的值不同:说明匹配失败,返回 false ;
2.代码实现
# -*- coding:utf-8 -*-
# class TreeNode:
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution:
def HasSubtree(self, pRoot1, pRoot2):
# write code here
#定义result
result=False
if pRoot1==None or pRoot2 ==None:
return False
#查看A,B的根节点是否相同
if pRoot1.val ==pRoot2.val:
result=self.helper(pRoot1,pRoot2)
if not result:
#将pRoot的左子树与pRoot2开始递归
result=self.HasSubtree(pRoot1.left, pRoot2)
if not result:
#将pRoot的右子树与pRoot2开始递归
result=self.HasSubtree(pRoot1.right, pRoot2)
return result
def helper(self,node1,node2):
#如果pRoot2是一个叶子节点或者是提前到达了叶子节点说明已经遍历结束
if node2==None:
return True
#如果是pRoot1先到达叶子节点,说明已经遍历完,此时pRoot2还没有遍历完
if node1==None:
return False
#如果此时的两个节点的值是相等的,则进入左子树与右子树值的判断
if node1.val==node2.val:
if self.helper(node1.left,node2.left)and self.helper(node1.right,node2.right):
return True
else:
return False
3. 总结
判定是否是树的子结构,递归的使用非常关键,树不仅是要数值最重要的是结构也需要相同。
所以第一步要是找出A、B两棵树中是否有值相同的节点,先判断根节点的值是否相同,相同则进入下一步helper()函数。如果两棵树根节点的值不同,则需要使用递归将A的左子树与B进行判断,如果遇到相同的点则进入下一步helper()函数。如果此时还没有判断出来,则需要对A的右子树与B进行判断,判定在A的右子树中是否有与B值相同的点。
第二步是进入到helper()函数,此函数的作用是判断进入此函数的两棵树是否有相同的结构,不仅要数值相同,而且结构也需要相同。需要注意的地方是首先判断传入函数的第二棵树是否是叶子节点,这里需要着重了解一下,因为在第一个函数HasSubtree()中进行了判断,如果A树的节点与B树的节点有相同的则进入到helper()函数中,进入到helper()函数中时,肯定是B的根节点与A的某一个节点是相同的,所以将以A的某个节点为根节点的结构与整个B树一同传进了helper()中,如果此时的B 仅仅是一个叶子节点,那B肯定是A的子结构,因为数值相同,并且是叶子节点;如果传进来的是A的一个叶子节点,但是此时B不为空,那肯定B就不是A的子结构;下面的需要注意一下,是判断两个值是否是相同的,这个判断值是否相同是在第一个函数中判断过了,此时需要判断的原因是需要进行递归,判断传入的树的左子树与B的左子树相同(值相同,结构相同)并且传入的树的右子树与B的右子树相同,那肯定就符合子结构的定义,返回True。