输入两棵二叉树A,B,判断B是不是A的子结构。(我们约定空树不是任意一个树的子结构)
假如给定A为{8,8,7,9,2,#,#,#,#,4,7},B为{8,9,2},2个树的结构如下,可以看出B是A的子结构
数据范围:
0 <= A的节点个数 <= 10000
0 <= B的节点个数 <= 10000
{8,8,7,9,2,#,#,#,#,4,7},{8,9,2}
true
{1,2,3,4,5},{2,4}
true
{1,2,3},{3,1}
false
/*public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } }*/ public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root2==null) return false; if(root1==null && root2!=null) return false; boolean flag = false; if(root1.val==root2.val){ flag = isSubTree(root1,root2); } if(!flag){ flag = HasSubtree(root1.left, root2); if(!flag){ flag = HasSubtree(root1.right, root2); } } return flag; } private boolean isSubTree(TreeNode root1, TreeNode root2) { if(root2==null) return true; if(root1==null && root2!=null) return false; if(root1.val==root2.val){ return isSubTree(root1.left, root2.left) && isSubTree(root1.right, root2.right); } return false; } }
public class Solution { public static boolean HasSubtree(TreeNode root1, TreeNode root2) { boolean result = false; //当Tree1和Tree2都不为零的时候,才进行比较。否则直接返回false if (root2 != null && root1 != null) { //如果找到了对应Tree2的根节点的点 if(root1.val == root2.val){ //以这个根节点为为起点判断是否包含Tree2 result = doesTree1HaveTree2(root1,root2); } //如果找不到,那么就再去root的左儿子当作起点,去判断时候包含Tree2 if (!result) { result = HasSubtree(root1.left,root2); } //如果还找不到,那么就再去root的右儿子当作起点,去判断时候包含Tree2 if (!result) { result = HasSubtree(root1.right,root2); } } //返回结果 return result; } public static boolean doesTree1HaveTree2(TreeNode node1, TreeNode node2) { //如果Tree2已经遍历完了都能对应的上,返回true if (node2 == null) { return true; } //如果Tree2还没有遍历完,Tree1却遍历完了。返回false if (node1 == null) { return false; } //如果其中有一个点没有对应上,返回false if (node1.val != node2.val) { return false; } //如果根节点对应的上,那么就分别去子节点里面匹配 return doesTree1HaveTree2(node1.left,node2.left) && doesTree1HaveTree2(node1.right,node2.right); } }
class Solution { bool isSubtree(TreeNode* pRootA, TreeNode* pRootB) { if (pRootB == NULL) return true; if (pRootA == NULL) return false; if (pRootB->val == pRootA->val) { return isSubtree(pRootA->left, pRootB->left) && isSubtree(pRootA->right, pRootB->right); } else return false; } public: bool HasSubtree(TreeNode* pRootA, TreeNode* pRootB) { if (pRootA == NULL || pRootB == NULL) return false; return isSubtree(pRootA, pRootB) || HasSubtree(pRootA->left, pRootB) || HasSubtree(pRootA->right, pRootB); } };
class Solution { public: bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) { if (pRoot2 == NULL || pRoot1 == NULL) return false; return dfs(pRoot1, pRoot2) || HasSubtree(pRoot1->left, pRoot2) || HasSubtree(pRoot1->right, pRoot2); } bool dfs(TreeNode* node, TreeNode* pRoot2) { if (pRoot2 == NULL) return true; else if (node != NULL) { return (node->val == pRoot2->val) && dfs(node->left, pRoot2->left) && dfs(node->right, pRoot2->right); } else return false; } };
public class Solution {
public boolean HasSubtree(TreeNode tree, TreeNode sub) {
return sub == null ? false : isSubtree(tree, sub);
}
private boolean isSubtree(TreeNode tree, TreeNode sub) {
if (sub == null) return true;
if (tree == null) return false;
if (tree.val == sub.val) {
boolean isSameTree = isSubtree(tree.left, sub.left) && isSubtree(tree.right, sub.right);
if (isSameTree) return true;
}
return isSubtree(tree.left, sub) || isSubtree(tree.right, sub);
}
}
/* 改进算法,时间复杂度O(m+n) * 1.将root1和root2分别按先序遍历序列化。 * 2.运用KMP算法匹配序列化结果。 */ public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root2==null) return false;// 空树本应是任意树的子结构,但从测试集来看,应视为false if(root1==null) return false; char[] str = Serialize(root1).toCharArray(); char[] pattern = Serialize(root2).toCharArray(); int[] next = new int[pattern.length]; System.out.println(String.valueOf(str)); System.out.println(String.valueOf(pattern)); getNext(pattern,next); return KMP(str,pattern,next); } private boolean KMP(char[] str, char[] pattern, int[] next) { if(str==null||pattern==null) return false; if(str.length<pattern.length) return false; int i=0,j=0,len = str.length; while(i<len&&j<pattern.length){ if(j==-1||str[i]==pattern[j]){ i++;j++; }else{ j = next[j]; } } if(j==pattern.length)// 表示最后一个字符也相等,匹配成功 return true; return false; } private void getNext(char[] pattern, int[] next) { if(pattern==null||pattern.length==0) return; int i=0,j=-1; next[0] = -1; while(i<pattern.length-1){ if(j==-1||pattern[i]==pattern[j]){ ++i;++j; if(pattern[i]==pattern[j]){ next[i] = next[j]; }else{ next[i] = j; } }else{ j = next[j]; } } } public String Serialize(TreeNode root) { if(root==null) return ""; this.buffer = new StringBuffer(); SerializeF(root); int i; // 删除序列尾部的$ for(i = buffer.length()-1;i>=0;i--){ if(buffer.charAt(i)==','||buffer.charAt(i)=='$'){ continue; }else break; } buffer.delete(i+1,buffer.length()); return buffer.toString(); }
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: bool isSub(TreeNode* p1, TreeNode* p2){ //非递归 if (!p2) return true; if (!p1) return false; return p1->val == p2->val && isSub(p1->left, p2->left) && isSub(p1->right, p2->right); } //中序遍历 bool HasSubtree(TreeNode* p1, TreeNode* p2) { if(!p2) return false; stack<TreeNode*> st; while(p1||!st.empty()){ while(p1){ if(p1->val==p2->val&&isSub(p1, p2)) return true; st.push(p1); p1=p1->left; } TreeNode* t=st.top(); st.pop(); p1=t->right; } return false; } };2. 递归
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: bool isSub(TreeNode* p1, TreeNode* p2) { //递归 if(!p2) return true; else if(!p1) return false; return p1->val==p2->val&&isSub(p1->left, p2->left)&&isSub(p1->right, p2->right); } bool HasSubtree(TreeNode* p1, TreeNode* p2) { if(!p1||!p2) return false; return isSub(p1, p2)||HasSubtree(p1->left, p2)||HasSubtree(p1->right, p2); } };
public class Solution { //使用该方法在root1上找与root2值相同的节点。 public boolean HasSubtree(TreeNode root1,TreeNode root2) { //当root1和root2中由任意一个是空的话,那直接返回false if(root1 == null || root2 == null) return false; //首先是要找到相同值的节点,然后从该节点判断root2是否是该节点的子结构 if(root1.val == root2.val){ //这里不是直接返回是否是子结构的判断结果,如果是直接返回判断结果的话则只是对一个节点上做了判断,没有向下继续判断 //这里是先判断当前是否是子结构,然后是子结构才返回true。不是子结构就去继续判断root1的左右子节点。 if(subTree(root1,root2)){ return true; } } //当前节点不满足再使用它的左右子节点递归判断。只要由一个子树包含root2树,即可返回true,故用|| return HasSubtree(root1.left,root2) || HasSubtree(root1.right,root2); } //判断root2是否是root1的子结构 public boolean subTree(TreeNode root1,TreeNode root2){ //当root2每个节点都判断完毕了,说明root2是root1的子结构 if(root2 == null) return true; //当roo2没判断完,而root1已经判断完了,说明root2不是root1的子结构 if(root1 == null) return false; //如果当前root1和root2的节点值相等,那么在去判断两者的子树。 if(root1.val == root2.val){ return subTree(root1.left,root2.left)&&subTree(root1.right,root2.right); } //反之root1.val和root2.val的值不相等,直接返回false return false; } }
public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { return (root1!=null&&root2!=null)&& (recur(root1,root2)||HasSubtree(root1.left,root2)||HasSubtree(root1.right,root2)); } boolean recur(TreeNode A,TreeNode B){ if(B==null)return true;//说明匹配完成 B是A的子结构 if(A==null||A.val!=B.val)return false;//A树为空或者节点值不相等 说明不是子结构 return recur(A.left,B.left)&&recur(A.right,B.right); } }
//Javascript 描述,用flag表示函数状态。 function HasSubtree(p1, p2,flag) { var f=HasSubtree; if(flag && !p2) return true; if(!p1 || !p2) return false; if(p1 && p2 && p1.val == p2.val) return f(p1.left,p2.left,true) && f(p1.right,p2.right,true) || f(p1.left,p2)||f(p1.right,p2); return f(p1.left,p2) || f(p1.right,p2); }
class Solution { public: bool isSubtree(TreeNode *t1, TreeNode *t2){ if(t2==NULL) return true; if(t1==NULL && t2!=NULL) return false; if(t1->val == t2->val){ bool lTree = isSubtree(t1->left, t2->left); bool rTree = isSubtree(t1->right, t2->right); return lTree && rTree; }else return false; } bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) { if(pRoot1 == NULL || pRoot2 == NULL) return false; return isSubtree(pRoot1, pRoot2) || HasSubtree(pRoot1->left, pRoot2) || HasSubtree(pRoot1->right, pRoot2); } };
public boolean HasSubtree(TreeNode root1, TreeNode root2) { if(root2 == null) { return false; } List<TreeNode> list1 = new ArrayList<>(); List<TreeNode> list2 = new ArrayList<>(); preOrderTraversal(root1, list1); preOrderTraversal(root2, list2); StringBuffer sb1 = new StringBuffer(); for (int i = 0; i < list1.size(); i++) { sb1.append(list1.get(i).val); } StringBuffer sb2 = new StringBuffer(); for(int i = 0; i < list2.size(); i++) { sb2.append(list2.get(i).val); } return sb1.toString().indexOf(sb2.toString()) >= 0 ? true : false; // return !list1.contains(list2); //是错误的做法,contains只能检测一个list钟是否包含某元素 } public void preOrderTraversal(TreeNode root, List<TreeNode> list) { if(root == null) { return; } list.add(root); preOrderTraversal(root.left, list); preOrderTraversal(root.right, list); }
class Solution { public: //递归判断,分条件 bool HasSubtree(TreeNode* p1, TreeNode* p2) { if(p1==NULL||p2==NULL) return false; return Hbtree(p1,p2); } bool Hbtree(TreeNode* p1, TreeNode* p2) { if(p2==NULL) return true; if(p1==NULL) return false; if(p1->val==p2->val) { if(Hbtree(p1->left,p2->left)&&Hbtree(p1->right,p2->right)) return true; } return Hbtree(p1->left,p2)||Hbtree(p1->right,p2); } };
如果最后没用debug,立的flag的错误估计我要print一天才能出来,这道题考虑的细节比较多 弄了3小时了: (迭代版层序遍历掌控全局)先在找到B树中的根结点在A树中的位置(注意,这个位置可能有多个,所以我这里用了 一个列表去保存这些可能的结点),然后以B树为基准,依次遍历,看看他们的左右孩子结点的值是 不是相同的,(刚开始我直接用的地址去判断,因为python中整数是不可变的,然而忽略掉了结点 本身已经是一个地址,每个结点的地址不一样,所以用地址去判断是错误的),最后就是要注意提前 结束没有必要的遍历,节省时间,不过最坏还是有n**2,还有很大上升空间。 class Solution: def HasSubtree(self, pRoot1, pRoot2): # write code here if not pRoot1 or not pRoot2: return False result1 = [] result2 = [] foundlst = [] found = True result1.append(pRoot1) while result1: tmp = result1.pop(0) if tmp.val == pRoot2.val: foundlst.append(tmp) if tmp.left: result1.append(tmp.left) if tmp.right: result1.append(tmp.right) while foundlst: result1.append(foundlst.pop(0)) result2.append(pRoot2) while result2: tmp1 = result1.pop(0) tmp2 = result2.pop(0) if tmp1.val != tmp2.val: found = False result1 = [] result2 = [] else: found = True if tmp1.left: result1.append(tmp1.left) if tmp1.right: result1.append(tmp1.right) if tmp2.left: result2.append(tmp2.left) if tmp2.right: result2.append(tmp2.right) if found == False: continue else: return True else: return False
public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { boolean result = false; if(root1!=null&&root2!=null){ if(root1.val==root2.val) result = DoesTree1HaveTree2(root1,root2); if(!result) result = HasSubtree(root1.left,root2); if(!result) result = HasSubtree(root1.right,root2); } return result; } boolean DoesTree1HaveTree2(TreeNode root1,TreeNode root2){ if(root2==null) return true; if(root1==null) return false; if(root1.val!=root2.val) return false; return DoesTree1HaveTree2(root1.left,root2.left)&&DoesTree1HaveTree2(root1.right,root2.right); } }
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) { // 时间复杂度O(NM),空间复杂度O(NM) if (pRoot1 == nullptr || pRoot2 == nullptr) return false; return dfs(pRoot1, pRoot2) || HasSubtree(pRoot1->left, pRoot2) || HasSubtree(pRoot1->right, pRoot2); } bool dfs(TreeNode *pRoot1, TreeNode *pRoot2) { if (pRoot2 == nullptr) return true; if (pRoot1 == nullptr) return false; if (pRoot1->val != pRoot2->val) return false; return dfs(pRoot1->left, pRoot2->left) && dfs(pRoot1->right, pRoot2->right); } };
/* struct TreeNode { int val; struct TreeNode *left; struct TreeNode *right; TreeNode(int x) : val(x), left(NULL), right(NULL) { } };*/ class Solution { public: bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2) { return (pRoot1 && pRoot2) && (recur(pRoot1, pRoot2) || HasSubtree(pRoot1->left, pRoot2) || HasSubtree(pRoot1->right, pRoot2)); } bool recur(TreeNode* A, TreeNode* B) { if (!B) return true; if (!A || A->val != B->val) return false; return recur(A->left, B->left) && recur(A->right, B->right); } };