题目
方法一-递归
算法思路
通过同步移动两个指针的方法来遍历这棵树,p和q一开始都指向这棵树的根,随后p左移时q右移,p右移时q左移,每移动一次都要检查当前两个指针所指的结点的值是否相等,相等再继续往下遍历。
设 i s S y m m e t r i c ( r o o t ) isSymmetric(root) isSymmetric(root) 用来判断以 r o o t root root 为根节点的树是否对称:
- 特例: r o o t root root 为 null ,直接返回 true
- 返回值: c h e c k ( r o o t . l e f t , r o o t . r i g h t ) check(root.left,\ root.right) check(root.left, root.right)
设
c
h
e
c
k
(
L
,
R
)
check(L,\ R)
check(L, R)用来判断分别以
L
L
L、
R
R
R 为根节点的树是否对称:
递推过程:
- 判断 L . l e f t L.left L.left 与 R . r i g h t R.right R.right 是否对称,即 c h e c k ( L . l e f t , R . r i g h t ) check(L.left,\ R.right) check(L.left, R.right);
- 判断 L . r i g h t L.right L.right 与 R . l e f t R.left R.left 是否对称,即 c h e c k ( L . r i g h t , R . l e f t ) check(L.right,\ R.left) check(L.right, R.left);
终止条件:
- 两树同时越过叶节点,返回 t r u e true true;
- 两树中只有一个越过叶节点,返回 f a l s e false false;
- 对应节点值不相等,返回 f a l s e false false。
返回值: c h e c k ( L . l e f t , R . r i g h t ) & & c h e c k ( L . r i g h t , R . l e f t ) check(L.left,\ R.right)\ \And\!\And\ check(L.right,\ R.left) check(L.left, R.right) && check(L.right, R.left)
具体代码
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null)return true;
return check(root.left, root.right);
}
private boolean check(TreeNode L, TreeNode R){
if(L == null && R == null)return true;
if(L == null || R == null || L.val != R.val)return false;
return check(L.left, R.right) && check(L.right, R.left);
}
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n),n为树的结点总数。每次执行 check() 可以判断一对节点是否对称,因此最多调用 n 2 \frac{n}{2} 2n 次 recur() 方法。
- 空间复杂度:
O
(
n
)
O(n)
O(n),最差情况下二叉树退化为链表,系统使用
O
(
n
)
O(n)
O(n) 大小的栈空间
方法二-迭代(队列)
算法思路
引入队列,初始时将根结点入队两次,每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,并且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中,当队列为空或检测到不对称(即从队列中取出的两个连续结点不相等)时算法结束。
注意:
这个迭代法,其实是把左右两个子树要比较的元素顺序放进一个容器,然后成对取出来进行比较,那么使用栈也是可以的。
具体代码
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root == null)return true;//空树一定对称
return check(root, root);
}
private boolean check(TreeNode u, TreeNode v){
Queue<TreeNode> q = new LinkedList<TreeNode>();//队列初始化
q.offer(u);q.offer(v);//根节点入队两次
//队列为空时结束循环
while(!q.isEmpty()){
//取队列中两个连续节点
u = q.poll();
v = q.poll();
//若两个节点均为null,转到下一轮循环
if(u == null && v == null)continue;
//若两个节点中只有一个为null,或对应值不等,直接返回false
if((u == null || v == null) || u.val != v.val)return false;
//将两个节点的左右子节点按相反的顺序插入队列
q.offer(u.left);
q.offer(v.right);
q.offer(u.right);
q.offer(v.left);
}
return true;
}
}
复杂度分析
- 时间复杂度: O ( n ) O(n) O(n),n为树的结点总数。
- 空间复杂度: O ( n ) O(n) O(n),额外使用 O ( n ) O(n) O(n) 大小的队列空间