题目描述
思路分析
这个题拿到手上,第一个思考的就是:如何正确的去解读“镜像对称”。第一个想法就是:既然每个形态不同的树,中序遍历结果不同,那么直接对树进行中序遍历,然后比较数组是否对称即可。
如上述问题描述中,第一个例子的中序遍历为:【3,2,4,1,4,2,3】,显然以中点对称。
第二个例子的中序遍历为:【2,3,1,2,3】,那么无法满足要求。
正当我兴高采烈地秒完中序遍历直接提交时,出错了。。。
当面对这个树时,中序遍历结果是对称的。
思路二
究其原因,是由于中序遍历结果把 null 忽略掉没有记录。
假如上面这个树的输出为:【2,2,n,1,2,2,n】,那么轻松的就可以判定这也不是对称的。
然而,如何在递归过程中写出,能够记录 null 的代码,我没有能够实现。因为递归就是靠 null 来判断边界的,我没法去利用这个值。
思路三
看完答案后,发觉是自己把自己的思路禁锢住了。
既然要判断对称,那么要求便是:左子树与右子树对称。
对称的要求是:
1. 左子树的左孩子等于右子树的右孩子
2. 左子树的右孩子等于右子树的左孩子
边界条件:
1 . 左子树与右子树同时为空
2 . 左右子树有一者为空
3 . 左右子树值不相同
显然,要求是收敛的,存在边界,那么可以写新的递归,递归参数即为左右子树根
public class Solution2 {
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
return isEqual(root.left, root.right);
}
public boolean isEqual(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;
boolean re1 = isEqual(left.left, right.right);
boolean re2 = isEqual(left.right, right.left);
return re1 && re2;
}
}
思路四
非递归写法,直接借用一个容器,来存储左右子树对应位置的节点。结束循环的边界即为:容器为空—树遍历结束。
public class Solution3 {
public boolean isSymmetric(TreeNode root) {
if (root == null) return true;
if (root.left == null && root.right == null) return true;
Stack<TreeNode> stack = new Stack<>();
stack.push(root.left);
stack.push(root.right);
while (!stack.isEmpty()) {
TreeNode left = stack.pop();
TreeNode right = stack.pop();
if (left == null && right == null) {
continue;
}
if (left == null || right == null) {
return false;
}
if (left.val != right.val) {
return false;
}
stack.add(left.left);
stack.add(right.right);
stack.add(left.right);
stack.add(right.left);
}
return true;
}
}
不一定要用栈,队列也可以。