目录
1. 题目描述
2. 解题思路
这道题目一开始我其实是并不想从纯结构方面去判断一个二叉树是否对称的,总感觉有没有一点稍微“高级”的方法,于是想起了昨天做的中序遍历,会不会利用中序遍历结果可以判断呢?那就一起来看看
看起来是似乎可以通过判断中序遍历输出是否回文数来间接判断这棵树是否对称,当我信心满满地提交代码后发现,对于这个树,我是错了的:
然后我又思考了片刻,发现:
似乎我又对了?代码提交!fine,还是有问题,什么问题呢?请看:
然后,我又依据这玩意构建了个满二叉树:
当我整完这一通操作之后,感觉这个做法似乎意义不大了,还得构建满二叉树,浪费时间浪费储存。然后我转而到了纯结构的路上了
纯结构的递归没什么好介绍的,无非就是分开左子树节点的左孩子与右子树节点的右孩子比较,左子树节点的右孩子与右子树节点的左孩子比较,仅此而已。
纯结构的迭代就有点意思了,但在递归中使用的是栈,先进后出,而在迭代中,我第一个想法是使用队列,先进先出,借鉴广度优先搜索的概念,对二叉树进行一层层处理,每处理一层则把该层的孩子(左子树的左孩子和右子树的右孩子,左子树的右孩子和右子树的左孩子)塞进队列中,若最后队列都为空则代表是对称结构了。
3. 代码实现
3.1 利用中序遍历(卒 | 小部分情况无法解决 除非构建满二叉树)
public boolean isSymmetric(TreeNode root) {
List<Integer> mid = middle(root);
System.out.println(Arrays.toString(mid.toArray()));
for (int i = 0, j = mid.size() - 1; i < j; i++, j--) {
if (mid.get(i) != mid.get(j))
return false;
}
return true;
}
public List<Integer> middle(TreeNode root) {
List<Integer> list = new ArrayList<>();
if (root != null) {
if (root.left == null && root.right == null) {
list.add(root.val);
} else {
list.addAll(middle(root.left));
list.add(root.val);
list.addAll(middle(root.right));
}
}else
list.add(null);
return list;
}
3.2 递归
public boolean isSymmetric(TreeNode root) {
return root == null || duibi(root.left, root.right);
}
public boolean duibi(TreeNode left, TreeNode right) {
if (left != null && right != null)
return left.val == right.val && duibi(left.left, right.right) && duibi(left.right, right.left);
return left == null && right == null;
}
这是本题我所提交的最好表现,官解的代码几乎也和我的一样,但是这内存消耗怎么才45%,奇怪
3.3 迭代
public boolean isSymmetric(TreeNode root) {
if (root != null) {
LinkedList<TreeNode> treeNodes = new LinkedList<>();
treeNodes.add(root);
TreeNode template;
while (!treeNodes.isEmpty()) {
template = treeNodes.removeFirst();
if (template.left == null && template.right == null)
continue;
if (template.left != null && template.right != null) {
if (template.left.val != template.right.val)
return false;
treeNodes.add(new TreeNode(0, template.left.left, template.right.right));
treeNodes.add(new TreeNode(0, template.left.right, template.right.left));
}else
return false;
}
return true;
}
return true;
}
3.4 对比
利用中序遍历的做法参考意义不大,这里就没有继续写构建二叉树的代码了,就递归和迭代而言,二者的时间复杂度都是O(n),而二者的空间复杂度都是O(n),本质上没有差别,但在迭代中我为了方便直接使用了TreeNode
类存储到队列中了,事实上val
并没有任何意义的,是一个冗余的参数,这应该也是迭代的内存消耗比递归大的原因。