1.题目
2.解法
public class Solution {
public boolean HasSubtree(TreeNode root1,TreeNode root2) {
if (root1 == null || root2 == null) return false;
// 之所以在这里加三种情况,是因为有可能有相同的点
// 比如根点为8,根点的子结点也为8,但是真正的子结构是从子结点开始的
return Judge(root1, root2) ||
Judge(root1.left, root2) ||
Judge(root1.right, root2);
}
public boolean Judge(TreeNode root1, TreeNode root2) {
// 这两个条件由递归式决定,有时候条件决定递归,有时候递归决定条件
// 我这部分比较完了,返回true
if (root2 == null) return true;
// 如果root1,没有根和root2比较,所以返回false
if (root1 == null) return false;
// 如果根不相等,root2有可能是左子树或者右子树的一部分
if (root1.val != root2.val) {
return Judge(root1.left, root2) || Judge(root1.right, root2);
}
return Judge(root1.left, root2.left) && Judge(root1.right, root2.right);
}
}
时间复杂度时间,最坏情况下,我们对于树A中的每个节点都要递归判断一遍,每次判断在最坏情况下需要遍历完树B中的所有节点。故时间复杂度是 O(nm) ,其中 n是树A中的节点数, m 是树B中的节点数。空间复杂度为递归栈的个数
3.错误总结
切入点:根相等
或者根不相等,有可能左右两树进行比较
递归条件
在主函数中写有几种情况就可。
1、
// 首先root2为空,root1也不一定为空,因为root2只是一部分
// 所以这里错误
if (root1 == null && root2 == null) return true;
// root1为空和root2为空两者代表的情况不一样
// 所以这里错误
if (root1 == null || root2 == null) return false;
2、
// 这两个条件由递归式决定,有时候条件决定递归,有时候递归决定条件
// 我这部分比较完了,返回true
if (root2 == null) return true;
// 如果root1,没有根和root2比较,所以返回false
if (root1 == null) return false;
4.相似的一道题(求树的子树)
(树的子结构指树的任意一部分,树的子树指它自己、和它的左右两子树,注意区分)
public class IsSubTree {
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 false;
}
return judgeSubTree(root1.left, root2.left) &&
judgeSubTree(root1.right, root2.right);
}
}