输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
这个题有两个种方法,一个是非递归方法,一个是递归方法。
但两种方法思路都是一样的,即对第一棵树进行遍历,在遍历的同时判断节点是否与第二颗树的根节点相等,若相等,比较同时遍历两颗树的节点,继续比较节点是否相等。若不相等,继续向下遍历。
1、非递归算法
- 这种方法思路也不难,但是使用队列来进行遍历无法解决对称的问题。
比如l,1.left=2和1,1.right=2。所以,笔者添加一个特殊的节点来当做空节点。避免了对称的问题,但是增加了逻辑的复杂度。
public static boolean HasSubtree(TreeNode root1, TreeNode root2) {
if (root1 == null || root2 == null) return false;
LinkedList<TreeNode> queue = new LinkedList<>();
TreeNode NullNode = new TreeNode(Integer.MAX_VALUE);
queue.add(root1);
//遍历第一棵树
while (!queue.isEmpty()) {
TreeNode treeNode = queue.pop();
if (treeNode != NullNode) {
if (treeNode.left != null) queue.offer(treeNode.left);
else queue.offer(NullNode);
if (treeNode.right != null) queue.offer(treeNode.right);
else queue.offer(NullNode);
}
//若节点与第二颗树的根节点相等。
if (treeNode.val == root2.val) {
LinkedList<TreeNode> queue1 = new LinkedList<>();
LinkedList<TreeNode> queue2 = new LinkedList<>();
queue1.add(treeNode);
queue2.add(root2);
//进入循环,同时遍历两颗树,比较两颗节点
while (true) {
TreeNode r1 = queue1.pop();
TreeNode r2 = queue2.pop();
if (r1.val != r2.val) break;
//r1
if (r1 != NullNode && (r1.left != null || r1.right != null)) {
if (r1.left != null) queue1.offer(r1.left);
else queue1.offer(NullNode);
if (r1.right != null) queue1.offer(r1.right);
else queue1.offer(NullNode);
}
//r2
if (r2 != NullNode && (r2.left != null || r2.right != null)) {
if (r2.left != null) queue2.offer(r2.left);
else queue2.offer(NullNode);
if (r2.right != null) queue2.offer(r2.right);
else queue2.offer(NullNode);
}
if ((r2.right == NullNode) || queue1.isEmpty() || queue2.isEmpty()) return true;
}
}
}
return false;
}
2、递归算法
- 好吧,比起非递归算法,递归算法看起来简洁得多。但递归算法得注意好判断条件,错了也不太好调试
public static boolean HasSubtree(TreeNode root1, TreeNode root2) {
if (root1 == null || root2 == null) return false;
return judge(root1, root2);
}
//遍历第一个子树同时检查第二棵树的根节点是否与节点相等,相等则调用isSame
public static boolean judge(TreeNode root1, TreeNode root2) {
if (root1 == null) return false;
if (root1.val == root2.val && isSame(root1, root2)) return true;
return judge(root1.left, root2) || judge(root1.right, root2);
}
//从某个节点开始,判断第二棵树是否为第一棵的子树
public static boolean isSame(TreeNode root1, TreeNode root2) {
if (root2 == null) return true;
if (root1 == null) return false;
if (root1.val != root2.val) return false;
return isSame(root1.left, root2.left) && isSame(root1.right, root2.right);
}