关于剑指Offer 树的子结构的讨论

第二次看到这个题还是不会....参考了这道题牛客网排名第一的答案,在理解的过程中,我认为这个答案有问题,如果是我理解错了,欢迎讨论指正。

关于树的子结构的定义,网上也没有很明确的说法,个人理解就是,只要小树是大树结构中的一部分就行。(子结构与子树一定要区分开来,最后会介绍两者区别。)

参考网上的博客得出的子树和子结构的区别:

子树的意思是包含了一个结点,就得包含这个结点下的所有节点,一棵大小为n的二叉树有n个子树,就是分别以每个结点为根的子树。子结构的意思是包含了一个结点,可以只取左子树或者右子树,或者都不取。

首先,根据剑指offer书上的测试用例,测试了牛客排名第一的答案。左边为大树,右边为小树,显然结果是true。

但是,他写的真的对吗?

按下面的代码构建两棵树进行测试,

/*
public class TreeNode {
      int val;
      TreeNode left;
      TreeNode right;
      TreeNode(int x) { val = x; }
  }
*/

public static void main(String[] args) {
        TreeNode root =new TreeNode(8);//大树根节点
        TreeNode r1=new TreeNode(8);
        TreeNode r2=new TreeNode(2);
        root.right=r2;
        root.left=r1;
        TreeNode r3=new TreeNode(9);
        TreeNode r4=new TreeNode(7);
        r1.right=r4;
        r1.left=r3;

        TreeNode target=new TreeNode(8);//小树根节点
        target.left=new TreeNode(9);
        target.right=new TreeNode(2);

        System.out.println(new Offer17().HasSubtree(root,target));
    }

即下图两棵树,显然右边不是左边的子结构,但是按他的代码却返回true。

  

这里贴出这位兄台的代码:

public class Solution {
    public boolean HasSubtree(TreeNode root1, TreeNode root2) {
        if (root1 == null || root2 == null) {
            return false;
        }
        return judgeSubTree(root1, root2) ||
               judgeSubTree(root1.left, root2) ||
               judgeSubTree(root1.right, root2);
    }
 
    private boolean judgeSubTree(TreeNode root1, TreeNode root2) {
        if (root2 == null) {
            return true;
        }
        if (root1 == null) {
            return false;
        }
        if (root1.val != root2.val) {
            return judgeSubTree(root1.left, root2) ||
                   judgeSubTree(root1.right, root2);
        }
        return judgeSubTree(root1.left, root2.left) &&
               judgeSubTree(root1.right, root2.right);
    }
}

在HasSubtree中的第一个judgeSubTree(root1, root2)就返回了true,显然错了。

其实思路应该分为两步:

1.在大树中找到和小树根节点相同的节点。

2.然后以此节点为根节点,在大树上往下搜索对比小书左右节点是否相同,不同则返回false

3.如果2步中最后返回false 回到第一步,从大树的左子树找和小树根节点相同的节点。

4.如果3步中最后返回false 回到第一步,从大树的右子树找和小树根节点相同的节点。

下面贴出按剑指Offer的代码,已测试通过。

public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(root1==null||root2==null) return false;
        boolean result=false;
        if(root1.val==root2.val){
            result = HasSubtreeHelper(root1,root2);
        }
        if(!result) result = HasSubtree(root1.left,root2);
        if(!result) result = HasSubtree(root1.right,root2);
        return result;
    }

    public boolean HasSubtreeHelper(TreeNode r1,TreeNode r2){
        if(r2==null) return true;
        if(r1==null) return false;
        if(r1.val!=r2.val) return false;
        return HasSubtreeHelper(r1.left,r2.left)&&HasSubtreeHelper(r1.right,r2.right);
    }

本人已入职Shopee,欢迎添加QQ群讨论算法/校招/go/java/内推:985288904

  • 18
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值