LeetCode-572. Subtree of Another Tree (Java)

来源:互联网 发布:不同的网络用户类型 编辑:程序博客网 时间:2024/06/04 18:20

Given two non-empty binary trees s and t, check whether tree t has exactly the same structure and node values with a subtree of s. A subtree of s is a tree consists of a node in s and all of this node's descendants. The tree s could also be considered as a subtree of itself.

Example 1:
Given tree s:

     3    / \   4   5  / \ 1   2
Given tree t:
   4   / \ 1   2
Return true, because t has the same structure and node values with a subtree of s.

Example 2:
Given tree s:

     3    / \   4   5  / \ 1   2    /   0
Given tree t:
   4  / \ 1   2
Return false.

--------------------------------------------------------------------------------------------------------------------------------

题意

求一个二叉树t是否是另一个二叉树s的子树,一个s子树由s中的一个节点以及这个节点的所有的后代组成。

思路

我的思路是:从s中节点值等于t的根节点值开始,遍历判断s的节点值与t的节点值是否相同,判断t的左或右孩子为空时,

s的左或右孩子情况,判断s的左或右孩子为空时,t的左右孩子情况。最终,测试用例只通过154个,并未全部通过。

其实,有另一种更简单、清晰的思路,就是遍历二叉树s和t,然后将他们的值拼接起来,最后再判断字符串是否包含t即可,

需要注意,这种方法需要在节点为空的时候添加具有标识的特殊字符,以便在具有相同树遍历方法的情况下,确定结构是否相同。

代码

public class Solution { public boolean isSubtree(TreeNode s, TreeNode t) {        String spreorder = generatepreorderString(s);         String tpreorder = generatepreorderString(t);                return spreorder.contains(tpreorder) ;    }    public String generatepreorderString(TreeNode s){        StringBuilder sb = new StringBuilder();        Stack<TreeNode> stacktree = new Stack();        stacktree.push(s);        while(!stacktree.isEmpty()){           TreeNode popelem = stacktree.pop();           if(popelem==null)              sb.append(",#"); // Appending # inorder to handle same values but not subtree cases           else                    sb.append(","+popelem.val);           if(popelem!=null){                stacktree.push(popelem.right);                    stacktree.push(popelem.left);             }        }        return sb.toString();    }}
这种方法号是比较长。

还有一种耗时比较短的方法:

private static boolean isSubtree(TreeNode s, TreeNode t, boolean isRoot) {//如果节点s和节点t都为空,则返回true        if (s == null && t == null) return true;        //如果节点s和t,有一个为空,另一个不为空,则返回false;        else if (s == null || t == null) return false;        //前两个if判断是根据树的结构进行判断,下面是在结构相同的前提下,判断节点的值是否相同        else {            //如果相同            if (s.val == t.val) {            //则递归继续进行判断,如果左子树和右子树都判断完了,并且都返回的true,则返回true。                if (isSubtree(s.left, t.left, true) && isSubtree(s.right, t.right, true)) return true;            } else {            //如果节点的值不相同,如果已经开始判断是否为子树,则返回false                if (isRoot) return false;            }            //如果s的左右孩子节点值与t的根节点值不同,则继续用s的左右孩子与t的根节点值比较。            //isRoot是用来判断是否开始对其子树进行判断。            ////为什么用或,因为t子树有可能在s的左子树或右子树。            return isSubtree(s.left, t, isRoot) || isSubtree(s.right, t, isRoot);        }            }

其实这个方法的思路和我的思路差不多,区别就是该方法的实现更合理。

首先,该方法有递归进行左右子树判断,而我是用非递归前序的遍历方法,而且我的方法用了三个stack,一个用于保存s,一个用于保存t,另一个用于保存当s的节点值等于t的根节点值时s的节点。而上面那个方法用一个标志位isRoot替代了我第三个stack的作用。其他对结果情况判断方面,我的方法和上面的方法是一致的。