剑指offer——树的子结构(还不错)

面18

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

思路:
采用两个方法,当头节点满足要求时,进入helper方法判定是否为子树。HasSubtree用于遍历所有可能的头节点情况。
整体采用递归的思路。


写代码的过程一直磕磕碰碰,感觉逻辑好不容易对了,但是一开始运行还是有错。提示:“运行超时:您的程序未能在规定时间内运行结束,请检查是否循环有错或算法复杂度过大。” 检查是否有死循环

错误代码:

public class Solution {
    boolean result = false;
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if (root1 == null || root2 == null)
            return false;
        else {
            while (root1 != null && root2 != null && result == false) { // while和递归同时出现,就是奔着死循环去的(?)
                if (root1.val != root2.val) {
                    result = HasSubtree(root1.left, root2);
                    if (result == true)
                        break;
                    result = HasSubtree(root1.right, root2);
                } else {
                    result = helper(root1, root2); // 死循环出现在这里,假设root1和root2值相等,因此进入了判断子结构环节,但后面的判断显示并非子树的情况下,这里缺少继续迭代,就会一直在这两个节点循环
                }
            }
            return result;
        }
    }

    public boolean helper(TreeNode root1,TreeNode root2){
        if(root1!=null&&root2!=null){
            if(root1.val!=root2.val){
                return false;
            }
            else{
                result = helper(root1.left,root2.left);
                result = helper(root1.right,root2.right);
            }
        }
        else if(root2==null)
            return true;
        return result;

    }    

}

修改了前面的部分,依旧错误:

测试用例:
{8,8,#,9,#,2,#,5},{8,9,#,3}

对应输出应该为:

false

你的输出为:

true

根据错误提示,直接定位到返回true的部分

    boolean result = false;
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if (root1 == null || root2 == null)
            return false;
        else {
            if (root1 != null && root2 != null && result == false) {
                if (root1.val != root2.val) {
                    result = HasSubtree(root1.left, root2);
                    if (result != true)
                    result = HasSubtree(root1.right, root2);
                } else {
                    result = helper(root1, root2);
                    if(result==false) {
                        root1.val = root1.val + 1; // 这里针对头节点满足要求但结果返回非子树的情况,把root1的值加1,下次迭代就会跳过这个节点,不会出现死循环
                        result = HasSubtree(root1,root2);
                    }
                }
            }
            return result;
        }
    }

    public boolean helper(TreeNode root1,TreeNode root2){
        if(root1!=null&&root2!=null){
            if(root1.val!=root2.val){
                return false;
            }
            else{
                result = helper(root1.left,root2.left);
                result = helper(root1.right,root2.right); // 这里绝对是有问题的,如果前一个result已经是false,这里判true就会改变result
            }
        }
        else if(root2==null)
            return true;
        return result;

    }

正确答案:
使用了&&后我发现之所以前面在写代码时觉得逻辑很麻烦,就是因为没有使用&&和||,导致判定的过程很繁琐。以及没有很好地理解递归。

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


                } else {
                    result = helper(root1, root2);
                    if(result==false) {
                        result = HasSubtree(root1.left, root2)|| HasSubtree(root1.right, root2);
                    }
                }
            }
            return result;
        }
    }

    public boolean helper(TreeNode root1,TreeNode root2){
        if(root1!=null&&root2!=null){
            if(root1.val!=root2.val){
                return false;
            }
            else{
               result = helper(root1.left,root2.left)&&helper(root1.right,root2.right);
            }
        }
        else if(root2==null)
            return true;
        return result;

    }

}

这里稍稍改变下顺序,代码看起来也会更有“逻辑”和简洁

public static boolean HasSubtree(TreeNode root1, TreeNode root2) {
        boolean flag = false;
        if (root1 != null && root2 != null) {
            if (root1.val == root2.val)
                flag = helper(root1, root2);
            if (!flag)
                flag = HasSubtree(root1.left, root2);
            if (!flag)
                flag = HasSubtree(root1.right, root2);
        }
            return flag;
    }

public boolean DoesTree1HaveTree2(TreeNode root1,TreeNode root2){
            if(root1 == null && root2 != null) return false;
            if(root2 == null) return true;
            if(root1.val != root2.val) return false;
            return DoesTree1HaveTree2(root1.left, root2.left) && DoesTree1HaveTree2(root1.right, root2.right);
        }

再加一种方法,HasSubTree中不用递归做,直接前序遍历A树,当找到子树时则停止遍历

import java.util.*;
public class Solution {
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        boolean result = false;
        if(root1==null||root2==null)
            return result;
        TreeNode temp;
        Stack<TreeNode> stack = new Stack<TreeNode>();
        stack.push(root1);
        while(!stack.isEmpty()&&result==false){
            temp = stack.pop();
            if(temp.val==root2.val)
                result = helper(temp,root2);
            if(temp.right!=null)
                stack.push(temp.right);
            if(temp.left!=null)
                stack.push(temp.left);

        }
        return result;
    }

    public boolean helper(TreeNode root1,TreeNode root2){
        if(root2==null)
            return true;
        if(root1==null)
            return false;
        if(root1.val!=root2.val)
            return false;
        if(root1.val==root2.val)
            return helper(root1.left,root2.left)&&helper(root1.right,root2.right);
        return true;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值