这是leetcode weekly contest31的第二题,easy题。要比较的是「子树」而非「子结构」。树的递归的题目不太好调试(其实也好调试的,就是testcase写起来麻烦)。
Editorial Solution里面提到三种approach:
Approach #1 Check All Subtrees [Accepted]
Approach #2 Using Preorder Traversal [Accepted]
Approach #3 By Comparison of Nodes [Accepted]
approach 3
我当时写的是第三种,先找到值相同的node,再比较这两个node是否代表相同的subtree。
Code:
public boolean isSubtree(TreeNode s, TreeNode t) {
//find node
boolean res = false;
if (s != null && t != null) {
if (s.val == t.val) {
res = checkSame(s, t);
}
if (!res) {
res = isSubtree(s.left, t);
}
if (!res) {
res = isSubtree(s.right, t);
}
}
return res;
}
private boolean checkSame(TreeNode s, TreeNode t) {
if (t == null && s == null) return true;
if (t == null || s == null) return false;
if (s.val != t.val) return false;
return checkSame(s.left, t.left) && checkSame(s.right, t.right);
}
还可以这样写:
public boolean isSubtree(TreeNode s, TreeNode t) {
return s != null && (checkSame(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t));
}
private boolean checkSame(TreeNode s, TreeNode t) {
if (t == null && s == null) return true;
if (s == null || t == null) return false;
if (s.val != t.val) return false;
return checkSame(s.left, t.left) && checkSame(s.right, t.right);
}
错误的示范
isSubtree的部分可以有很多种写法,可以用上面的one-liner,但是不能这么写,能看出为什么吗:
public boolean isSubtree(TreeNode s, TreeNode t) {
if (s!=null){
if (s.val == t.val) return checkSame(s , t );
else return isSubtree(s.left , t) || isSubtree(s.right , t);
}
return false ;
// return s != null && (checkSame(s, t) || isSubtree(s.left, t) || isSubtree(s.right, t));
}
因为上面这段代码跟注释掉的1-liner相比,在找到两个相同的节点后并没有再去判断s的孩子是否还和t的value相同。相当于s.val和t.val跟后面的else是与的关系了而不是或的关系。[1,1][1]的test case过不了。
如果要判断是否是「子结构」而不是「子树」
如果要判断是否是「子结构」而不是「子树」 , checkSame这样写:
private boolean checkSame(TreeNode s, TreeNode t) {
if (t == null) return true ;
if (s == null) return false ;
if (s.val != t.val) return false;
return checkSame(s.left, t.left) && checkSame(s.right, t.right);
}
递归真是博大精深。。
approach 1
遍历所有子树,加入到set里去,贴在下面:
public class Solution {
HashSet<String> trees = new HashSet<>();
public boolean isSubtree(TreeNode s, TreeNode t) {
String tree = inorder(t);
findAllSubTrees(s);
return trees.contains(tree);
}
public String findAllSubTrees(TreeNode s) {
if (s == null) {
return "";
}
String val = findAllSubTrees(s.left) + s.val + findAllSubTrees(s.right);
trees.add(val);
return val;
}
public String inorder(TreeNode t) {
if (t == null)
return "";
return inorder(t.left) + t.val + inorder(t.right);
}
}
approach 2
traversal,用indexOf判断是不是substring。事实证明,用inorder也可以的。
public class Solution {
HashSet < String > trees = new HashSet < > ();
public boolean isSubtree(TreeNode s, TreeNode t) {
String tree1 = preorder(s, true);
String tree2 = preorder(t, true);
System.out.println(tree1);
System.out.println(tree2);
return tree1.indexOf(tree2) >= 0;
}
public String preorder(TreeNode t, boolean left) {
if (t == null) {
if (left)
return "lnull";
else
return "rnull";
}
return "#"+t.val + " " +preorder(t.left, true)+" " +preorder(t.right, false);
}
}