详解二叉树递归经典例题——树的子结构

例题

输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

思路

基本思路

要查找树A内是否包含树B,首先,先在树A中查找是否存在和树B根节点的值一样的结点R。若存在,则对比R的子树与B子树是否相同;若不存在,则在R的子树中继续寻找是否存在和树B根节点的值一样的结点R。

如上图所示,首先我们在树A中找到跟树B值一样的节点:8,而后遍历两者子树,树A中节点8的左子节点为8,树B中节点8的左子节点为9,两个节点不同,判False。

于是,遍历根节点8的左右子树,其中在左子树中,根节点也为8=树B根节点,8的左子节点为9=树B中8的左子节点9,8的右子节点为2=树B中8的右子节点2,树B中2无子节点而树A中的2有子节点,但我们无须去理会,毕竟我们已经找到了,所以判True(但如果树B有,树A没有,那么判False)。

因此,我们仍需要遍历树A,接着查找值为8的节点。我们在树的第二层找到了一个值为8的节点,然后进行第二步判断,即判断这个节点下面的子树是否含有和树B一样结构的子树。于是我们遍历这个节点下面的子树,先后得到两个子节点9和2,这和B树的结构完全相同。此时我们在树A中找到了一个和树B的结构一样的子树,因此树B是树A的子结构。

第一步在树A中查找与根节点一样的节点,实际上就是树的遍历,可以采用递归的方式,代码如下:

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None    
   def HasSubtree(self, pRoot1: TreeNode, pRoot2: TreeNode):
        flag = False
        if pRoot2 is None:
            return False
        if pRoot1 is None and pRoot2 is not None:
            return False
        if pRoot1.val == pRoot2.val:
            flag = self.isSubTree(pRoot1, pRoot2)
        if flag is False:
            flag = self.HasSubtree(pRoot1.left, pRoot2)
            if flag is False:
                flag = self.HasSubtree(pRoot1.right, pRoot2)
        return flag

第二步是判断树A中以R为根节点的子树是不是和树B具有相同的结构。同样,我们也可以用递归的思路来考虑:如果节点R的值和树B的根节点不相同,则以R为根节点的子树和树B肯定不具有相同的结点;如果它们的值相同,则递归地判断它们各自的左右节点的值是不是相同。递归的终止条件是我们到达了树A或者树B的叶节点,代码如下:

    def isSubTree(self, root1:TreeNode, root2: TreeNode):
        if root2 is None:  # 走到这一步,树B没有节点了,不管树A是否有,都是返回True
            return True
        if root1 is None and root2 is not None:  # 但如果树B有节点但树A没了,那妥妥的False
            return False
        if root1.val == root2.val:  # 两者节点值相同,则递归其子树判断是否存在相同子结构
            return self.isSubTree(root1.left, root2.left) and self.isSubTree(root1.right, root2.right)
        return False

完整代码

class Solution:

    def HasSubtree(self, pRoot1: TreeNode, pRoot2: TreeNode):
        flag = False
        if pRoot2 is None:
            return False
        if pRoot1 is None and pRoot2 is not None:
            return False
        if pRoot1.val == pRoot2.val:
            flag = self.isSubTree(pRoot1, pRoot2)
        if flag is False:
            flag = self.HasSubtree(pRoot1.left, pRoot2)
            if flag is False:
                flag = self.HasSubtree(pRoot1.right, pRoot2)
        return flag

    def isSubTree(self, root1:TreeNode, root2: TreeNode):
        if root2 is None:
            return True
        if root1 is None and root2 is not None:
            return False
        if root1.val == root2.val:
            return self.isSubTree(root1.left, root2.left) and self.isSubTree(root1.right, root2.right)
        return False


if __name__ == '__main__':
    root = TreeNode('3')
    root.left = TreeNode('1')
    root.right = TreeNode('6')
    root.right.left = TreeNode('4')
    root.right.right = TreeNode('9')

    root1 = TreeNode('5')
    root.right = TreeNode('6')
    root.right.left = TreeNode('5')
    root.right.right = TreeNode('9')
    s = Solution()
    print(s.HasSubtree(root, root1))

输出:True

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

越来越胖的GuanRunwei

祝老板们身体健康,财源广进!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值