输入两棵二叉树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
import java.util.*; /** public class TreeNode { int val = 0; TreeNode left = null; TreeNode right = null; public TreeNode(int val) { this.val = val; } } */ /** * NC273 树的子结构 * @author d3y1 */ public class Solution { private boolean isSubtree = false; public boolean HasSubtree(TreeNode root1, TreeNode root2){ return solution1(root1, root2); // return solution2(root1, root2); } /** * 递归: 前序遍历 * @param root1 * @param root2 * @return */ private boolean solution1(TreeNode root1, TreeNode root2){ if(root1==null || root2 == null){ return false; } preOrder(root1, root2); return isSubtree; } /** * 前序遍历 * @param root1 * @param root2 */ private void preOrder(TreeNode root1, TreeNode root2){ if(isSubtree){ return; } if(root1 == null){ return; } if(root1.val == root2.val){ isSubtree = verify(root1, root2); } preOrder(root1.left, root2); preOrder(root1.right, root2); } /** * 校验: 递归 * @param root1 * @param root2 * @return */ private boolean verify(TreeNode root1, TreeNode root2){ if(root2 == null){ return true; } if(root1==null || root1.val!=root2.val){ return false; }else{ return verify(root1.left, root2.left) && verify(root1.right, root2.right); } } /** * 迭代: 层序遍历 * @param root1 * @param root2 * @return */ private boolean solution2(TreeNode root1, TreeNode root2){ if(root1==null || root2 == null){ return false; } levelOrder(root1, root2); return isSubtree; } /** * 层序遍历 * @param root1 * @param root2 */ private void levelOrder(TreeNode root1, TreeNode root2){ Queue<TreeNode> queue1 = new LinkedList<>(); queue1.offer(root1); TreeNode node1; while(!queue1.isEmpty()){ node1 = queue1.poll(); if(node1.val == root2.val){ isSubtree = check(node1, root2); if(isSubtree){ return; } } if(node1.left != null){ queue1.offer(node1.left); } if(node1.right != null){ queue1.offer(node1.right); } } } /** * 校验: 队列 * @param root1 * @param root2 * @return */ private boolean check(TreeNode root1, TreeNode root2){ Queue<TreeNode> queue1 = new LinkedList<>(); Queue<TreeNode> queue2 = new LinkedList<>(); queue1.offer(root1); queue2.offer(root2); TreeNode node1,node2; while(!queue2.isEmpty()){ node1 = queue1.poll(); node2 = queue2.poll(); if(node1==null || node1.val!=node2.val){ return false; } if(node2.left != null){ queue1.offer(node1.left); queue2.offer(node2.left); } if(node2.right != null){ queue1.offer(node1.right); queue2.offer(node2.right); } } return true; } }
import java.util.*; /** 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; dfs(root1, root2); return flag; } boolean flag = false; private void dfs(TreeNode root1, TreeNode root2) { if (root1 == null) { return ; } if (flag) { return ; } flag = isSubtree(root1, root2); if (flag) { return ; } dfs(root1.left, root2); dfs(root1.right, root2); } private boolean isSubtree(TreeNode root1, TreeNode root2) { if (root2 == null) { return true; } if (root1 == null) { return false; } if (root1.val != root2.val) { return false; } boolean left = isSubtree(root1.left, root2.left); boolean right = isSubtree(root1.right, root2.right); return left && right; } }
public class Solution { private boolean JudgeLocContain(TreeNode root1, TreeNode root2) { //JudgeLocContain方法为‘当前位置包含判断’ //用于比较 ‘A树root1位置的子树’ 是否包含 B树 //且只将B树与‘包括root1节点的 靠上部分的树’进行比较,判断是否包含 if (root1 == null && root2 == null) { return true; //root1和root2同时遍历,刚好一起比较完毕,说明root1和root2相同,返回true } if (root1 != null && root2 == null) { return true; /*此处root2为空代表B树已递归完毕,A树还未完毕,B树与A树之前的结构相同 题中“约定空树不是任意一个树的子结构” 针对 B树这个整体 但该方法是对 A树当前位置子树 和 B树 “逐个节点”校验,而判断是否包含 所以只需要在主方法开始阶段判断B树是否为空即可,此处不必考虑空树约定*/ } if (root1 == null && root2 != null) { return false; } //root1已完毕,root2还未完毕,说明两者不同 //此处隐含的剩下一种情况就是两者都还未完毕(两者都不为空,即可以比较两者值) if (root1.val != root2.val) { return false; }//排除两者值不相等的情况,取相等情况返回递归,保证了之前访问的节点相同 return JudgeLocContain(root1.left, root2.left) && JudgeLocContain(root1.right, root2.right); } public boolean HasSubtree(TreeNode root1, TreeNode root2) { if (root2 == null) { //按照约定,判断B树整体是否为空 return false; } if (root1 == null) {//root1为空,肯定不包含root2 return false; } /*隐含的情况是root1和root2都不为空 进行当前位置包含判断JudgeLocContain,并递归左右子树*/ return JudgeLocContain(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); } }
public class Solution { public boolean HasSubtree(TreeNode root1, TreeNode root2) { if (root2 == null || root1 == null) return false; if (root2.val == root1.val) if (HasDirectSubtree(root1.left, root2.left) && HasDirectSubtree(root1.right, root2.right)) return true; return HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); } /** 判断 root2 是否为 root1 的直接子树 */ private boolean HasDirectSubtree(TreeNode root1, TreeNode root2) { if (root1 == null && root2 == null) return true; else if (root1 == null) return false; else if (root2 == null) return true; if (root1.val != root2.val) return false; return HasDirectSubtree(root1.left, root2.left) && HasDirectSubtree(root1.right, root2.right); } }直接子树指的是从根节点开始比较的结果
//可以用双重递归的思想,对于A树的每个节点,判断它是不是和B树是相同的树,如果A有这样的节点,以它开头有和B树完全一样的树,即B是A的子树 public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { //如果root1为空或者root2为空,那么就无法继续递归下去看看有没有子树符合要求了,就直接返回false if(root1==null || root2==null){ return false; } //如果A树中有这么一个root,以它开头的树有一部分和B树完全一样,那么就认为A树包含B树 if(judge(root1,root2)){ return true; } //对以A树每个节点开头的树,如果任何一个树满足条件,都会返回true return HasSubtree(root1.left,root2)||HasSubtree(root1.right,root2); } public boolean judge(TreeNode root1,TreeNode root2){ //同时遍历root1开头的树和B树,如果遍历到B树这个节点为空了,说明之前都没发生过违法行为,返回true //注意 B树节点为空的时候,A树这个节点是可以有值的 if(root2==null){ //以B树为主,B树是宝宝,整个安全的不返回false的遍历完B树就算成功 return true; } //如果走到这了,B树这个节点不为空,那么如果此时A树这个节点为空,那么显然不符合要求 if(root1==null){ return false; } //如果走到这个,说明这两个节点同时不为空,那么如果它们的值不相同,它们也不是完全相同的一棵树 if(root1.val!=root2.val){ return false; } //这个节点的左子树的每个节点和右子树的每个节点都得符合要求,但凡有一对节点不符合要求返回false的,就整个失败 return judge(root1.left,root2.left) && judge(root1.right, root2.right); } }
public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root2 == null){ return false; } return Same(root1, root2); } boolean Same(TreeNode root1,TreeNode root2){ if(root2 == null){ return true; } if(root1 == null){ return false; } if(root1.val == root2.val){ if(Same(root1.left, root2.left) && Same(root1.right, root2.right)) return true; } return Same(root1.left, root2) || Same(root1.right, root2); } }
public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root2 == null || root1 == null){ return false; } if(root1.val == root2.val){ if( (root2.left == null || HasSubtree(root1.left, root2.left)) && (root2.right == null || HasSubtree(root1.right, root2.right))){ return true; } } return HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); } }
public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root1==null||root2==null) return false; return dps(root1,root2); } public boolean dps(TreeNode root1,TreeNode root2){ if(root2==null) return true; if(root1==null) return false; if(root1.val==root2.val&&dps(root1.left,root2.left)&&dps(root1.right,root2.right)) return true; else return dps(root1.left,root2)||dps(root1.right,root2); } }
public class Solution { public boolean HasSubtree(TreeNode root1, TreeNode root2) { //当一个节点存在另一个不存在时 if (root1 == null || root2 == null) return false; if (root1.val == root2.val && curd(root1.left, root2.left) && curd(root1.right, root2.right)) { return true; } return HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); } public boolean curd(TreeNode A, TreeNode B) { if (B == null) { return true; } if (A == null) { return false; } if (A.val == B.val) { return curd(A.left, B.left) && curd(A.right, B.right); } else { return false; } } }
public class Solution { public boolean HasSubtree(TreeNode root1, TreeNode root2) { //第一步,先确定起始比较位置 if (root1 == null || root2 == null) { return false; } boolean ans = false; //确立起始比较位置,从该位置尝试比较 if (root1.val == root2.val) { ans = isSameFromBegin(root1, root2); } //说明root1.val != root2.val&nbs***bsp;上面的起始位置不满足需求,换一个起始位置 if (ans != true) {//在左子树中找找 ans = HasSubtree(root1.left, root2); } if (ans != true) {//在右子树中找找 ans = HasSubtree(root1.right, root2); } return ans; } private boolean isSameFromBegin(TreeNode root1, TreeNode root2) { if (root2 == null) {//roo2为null,说明已经比较完了 return true; } if (root1 == null){ //root1为空,说明beginSub不是你的子树 return false; } if (root1.val != root2.val){//说明整树中,有不相等的节点 return false; } //分别比较左右左右子树,必须都是相等的 return isSameFromBegin(root1.left,root2.left) && isSameFromBegin(root1.right,root2.right); } }
/** 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 (root1 == null || root2 == null) return false; return isSame(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); } public boolean isSame(TreeNode root1, TreeNode root2) { if (root2 == null) return true; if (root1 == null || root1.val != root2.val) return false; return isSame(root1.left, root2.left) && isSame(root1.right, root2.right); } }
public class Solution { public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root1 == null || root2 == null) return false; return dfs(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); } // 不是完全比较两颗树完全相同,而是p覆盖了q private boolean dfs(TreeNode p, TreeNode q) { if(q == null) return true; if(p == null) return false; if(p.val != q.val) return false; return dfs(p.left, q.left) && dfs(p.right, q.right); } }
public class Solution { public boolean HasSubtree(TreeNode root1, TreeNode root2) { if (root1 == null || root2 == null)return false; return trySubtree(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right, root2); } boolean trySubtree(TreeNode p1, TreeNode p2) { if (p2 == null)return true; if (p1 == null || p1.val != p2.val)return false; if (p1.val == p2.val && trySubtree(p1.left, p2.left) && trySubtree(p1.right, p2.right))return true; return false; } }
public class Solution { public boolean isSame(TreeNode root1,TreeNode root2){ //如果root2为空,则为true(不需要考虑root1的状况) if(root2 == null) return true; if(root1 == null) return false; //判断首节点的值,然后root1与root2的左子树,然后root1与root2的右子树 return root1.val == root2.val && isSame(root1.left, root2.left) && isSame(root1.right, root2.right); } public boolean HasSubtree(TreeNode root1,TreeNode root2) { if(root1 == null || root2 == null) return false; return isSame(root1, root2) || HasSubtree(root1.left, root2) || HasSubtree(root1.right,root2); } }