leetcode刷题 572. 另一棵树的子树,Easy (Java)DFS&暴力+DFS&KMP

本文提供LeetCode 572题“另一棵树的子树”的两种解法:一种是基于深度优先搜索(DFS)的暴力解法,另一种是结合DFS与KMP算法的高效解法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.题目描述

给你两棵二叉树 rootsubRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

示例 1:

image.png

输入: root = [3,4,5,1,2], subRoot = [4,1,2]
输出: true

示例 2:

image.png

输入: root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]
输出: false

提示:

  • root 树上的节点数量范围是 [1, 2000]
  • subRoot 树上的节点数量范围是 [1, 1000]
  • -104 <= root.val <= 104
  • -104 <= subRoot.val <= 104

来源:力扣(LeetCode)
链接:572. 另一棵树的子树
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

2.题解

2.1 DFS&暴力(深度优先搜索)

2.1.1 思路

写了比题解简洁的递归,因为递归层数减少了,执行速度也比题解的答案快很多。

  • 一个是isSubtree函数,也就是判断是否为子树。首先如果子树为空肯定为子树;其次如果根为空,那说明根的层数比子树浅,所以不为子树;最后判断目标子树是否为根的子树以及根的左右子树是否有目标子树。
  • 还有一个isSametree函数,也就是判断这两棵树是否相等。先排除两者都为空;如果有一者为空,那么肯定不相同;最后判断值。如果值相同则可以判断左右子树是否相同。

tips:需要关注返回值中的且和或,子树是其中有一者为子树就为真,所以用或;而相同需要左右子树相同,所以要用且。

2.1.2 Java代码

class Solution {
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(subRoot == null){
            return true;
        }
        if(root == null){
            return false;
        }
        return isSametree(root,subRoot)||isSubtree(root.left,subRoot)||isSubtree(root.right,subRoot);
    }
    public boolean isSametree(TreeNode root,TreeNode subRoot){
        if(root == null &&subRoot == null){
            return true;
        }
        if(root == null || subRoot == null){
            return false;
        }
        if(root.val != subRoot.val){
            return false;
        }
        return isSametree(root.right,subRoot.right)&&isSametree(root.left,subRoot.left);   
    }
}

2.2 DFS&KMP

2.2.1 思路

是因为树的先序遍历是按照顺序的,所以可以将树的结构改成数组的结构,然后通过KMP来实现数组的对比。
对KMP不了解的可以看,字符串匹配KMP.
就通过root树和所求的子树通过DFS形成一个先序的数组,之后通过KMP进行对比。如果其中有子数组则返回true;反之则为false。

2.2.2 Java代码

class Solution {
    List<Integer> rootOrder = new ArrayList<>();
    List<Integer> subRootOrder = new ArrayList<>();
    int leftNull = 100001,rightNull = 100002;
    public boolean isSubtree(TreeNode root, TreeNode subRoot) {
        if(root == null){
            return false;
        }
        makeOrder(root,rootOrder);
        makeOrder(subRoot,subRootOrder);
        return kmp(rootOrder,subRootOrder);
    }
    public void makeOrder(TreeNode tree,List<Integer> order){
        if(tree == null){
            return;
        }
        order.add(tree.val);
        if(tree.left != null){
            makeOrder(tree.left,order);
        }
        else{
            order.add(leftNull);
        }
        if(tree.right != null){
            makeOrder(tree.right,order);
        }
        else{
            order.add(rightNull);
        }
    }
    public boolean kmp(List<Integer> rootO,List<Integer> subRootO){
        int n = rootO.size(),m = subRootO.size();
        int[] prefix = new int[m];
        for(int i =1,j=0;i<m;i++){
            while(j>0&&!subRootO.get(i).equals(subRootO.get(j))){
                j = prefix[j-1];
            }
            if(subRootO.get(i).equals(subRootO.get(j))){
                j++;
            }
            prefix[i] = j;
        }
        for(int i =0,j=0;i<n;i++){
            while(j>0&&!rootO.get(i).equals(subRootO.get(j))){
                j = prefix[j-1];
            }
            if(rootO.get(i).equals(subRootO.get(j))){
                j++;
            }
            if(j==m){
                return true;
            }
        }      
        return false;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值