什么是对称性递归?就是对一个对称的数据结构(这里指二叉树)从整体的对称性思考,把大问题分解成子问题进行递归,即不是单独考虑一部分(比如树的左子树),而是同时考虑对称的两部分(左右子树),从而写出对称性的递归代码。
一、判断B是否是A的子树
/**
* 先序遍历树A中的每个节点nA 函数: isSubStructure(A, B))
* 判断树 AA 中 以 nA为根节点的子树 是否包含树B。(对应函数 recur(A, B))
*/
public class Num26_B是否是A的子树 {
private class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public boolean isSubStructure(TreeNode A, TreeNode B) {
if(A==null&&B==null){
return true;
}
if(A==null||B==null){
return false;
}
//recur:A中是否包含B
return recur(A,B)||isSubStructure(A.left,B)||isSubStructure(A.right,B);
}
//方法1(更优)
// //判断A中是否包含B
// private boolean recur(TreeNode A, TreeNode B) {
// if(B==null){
// //B走到null,B遍历完毕了,说明B一定在A中包含。不包含的话中间值不等时就会直接退出
// return true;
// }
// if(A==null){
// //走到最后了A还在遍历,说明没有值匹配
// return false;
// }
// if(A.val!=B.val){
// return false;
// }
// //值相等,继续遍历下一个左右子树对应结点
// return recur(A.left,B.left)&&recur(A.right,B.right);
// }
//方法2:判断A和BA.left和B或A.right和B是否相等【判断pq是否相等,相等则true,包含关系】
public boolean recur(TreeNode p, TreeNode q) {
if(p==null&&q==null){
return true;
}
if(p!=null&&q==null){//注意这一步,当A没有遍历完但B走到了最后,说明B的值在A中已经连续找到完了,也是包含关系。如[10 12 6 8 3 11][10 12 6 8]
return true;
}
if(p==null){//A走到最后还没有值
return false;
}
if(p.val!=q.val){//两棵树根节点的值不相等
return false;
}
//此时两个根节点值相等,再判断子树是否值相等
return recur(p.left, q.left) && recur(p.right, q.right);
// return p.val==q.val&& isSameTree(p.left, q.left) && isSameTree(p.right, q.right);//上面几行的简写
}
}
二、二叉树镜像问题
1.得到一个二叉树镜像后的二叉树
思路:
1)将二叉树的左子树和右子树部分分别镜像,左子树返回根节点left,右子树返回right,left和right分别是根节点的左右子树;
2)再将镜像后的左右子树整体镜像,根节点的左子树挂在镜像后的右树上,root.right挂在left上(root.left=right;root.right=left)
/**
* 从根节点开始,递归地对树进行遍历,并从叶子节点先开始翻转得到镜像。
* 如果当前遍历到的节点 root 的左右两棵子树都已经翻转得到镜像,那么我们只需要交换两棵子树的位置
* 即可得到以root为根节点的整棵子树的镜像
* 链接:https://leetcode.cn/problems/er-cha-shu-de-jing-xiang-lcof/solution/er-cha-shu-de-jing-xiang-by-leetcode-sol-z44i/
**/
//输入一个二叉树,输出它的镜像
public class Num27_二叉树的镜像 {
private class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
//二叉树的镜像
public TreeNode mirrorTree(TreeNode root) {
if(root==null){
return null;
}
//遍历得到左子树和右子树,将左右子树分别镜像。再交换位置整体镜像左右子树
TreeNode left=mirrorTree(root.left);
TreeNode right=mirrorTree(root.right);
//左右子树分别已经镜像好了,把左右再整体镜像:root.left=right;root.right=left
root.left=right;
root.right=left;
return root;
}
}
2.对称二叉树
思路:对称二叉树左右子树存在镜像关系,只要两棵子树镜像相等,则二叉树对称(只需要判断根节点是否相等,左.left==右.right,左.right==右.left即可)
//请实现一个函数,用来判断一棵二叉树是不是对称的。如果一棵二叉树和它的镜像一样,那么它是对称的
/**
* 对称二叉树左右子树存在镜像关系,只要两棵子树镜像相等,则对称(只需要判断根节点是否相等,左.left==右.right,左.right==右.left即可)
*/
public class Num28_对称二叉树 {
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
}
public boolean isSymmetric(TreeNode root) {
if(root==null){
return true;
}
return isMirror(root.left,root.right);
}
//判断这两个左右子树是否镜像相等
private boolean isMirror(TreeNode left, TreeNode right) {
if(left==null&&right==null){
return true;
}
if(left==null||right==null){
return false;
}
if(left.val!=right.val){//左子树根节点和右子树根节点
return false;
}
//结点相等,继续向下遍历判断左子树的左右子树分别与右子树的右左子树是否镜像相等
return isMirror(left.left,right.right)&&isMirror(left.right,right.left);
}
}