剑指 Offer 28. 对称的二叉树
思路
一开始想用左根右遍历的序列和右根左遍历的序列进行比较,如果相等则镜像对称。后来发现这种方式不对,比如样例[1, 2, 2, null, 2]就不是镜像对称的,但这种方法会返回true。
方法一:递归
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 bool isSymmetric(TreeNode* root) { 13 if(root == NULL) 14 return true; 15 return check(root->left, root->right); 16 } 17 18 bool check(TreeNode* L, TreeNode* R) { 19 if(L == NULL && R == NULL) 20 return true; 21 22 if(L != NULL && R != NULL && L->val == R->val) 23 return check(L->left, R->right) && check(L->right, R->left); 24 25 return false; 26 } 27 28 };
复杂度分析:
时间复杂度 O(N) : 其中 N 为二叉树的节点数量,每次执行 check() 可以判断一对节点是否对称,因此最多调用 N/2 次 check() 方法。
空间复杂度 O(N) : 最差情况下,二叉树退化为链表,系统使用 O(N)大小的栈空间。
方法二:非递归(迭代)
方法一中我们用递归的方法实现了对称性的判断,那么如何用迭代的方法实现呢?
首先我们引入一个队列,这是把递归程序改写成迭代程序的常用方法。
初始化时我们把根节点入队两次。每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中。
当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 class Solution { 11 public: 12 bool isSymmetric(TreeNode* root) { 13 if(root == NULL) 14 return true; 15 return check(root->left, root->right); 16 } 17 18 bool check(TreeNode *u, TreeNode *v) { 19 queue <TreeNode*> q; 20 q.push(u); q.push(v); 21 while (!q.empty()) { 22 u = q.front(); q.pop(); 23 v = q.front(); q.pop(); 24 if (!u && !v) continue; 25 if ((!u || !v) || (u->val != v->val)) return false; 26 27 q.push(u->left); 28 q.push(v->right); 29 30 q.push(u->right); 31 q.push(v->left); 32 } 33 return true; 34 } 35 };
复杂度分析:
时间复杂度:O(n),同「方法一」。
空间复杂度:这里需要用一个队列来维护节点,每个节点最多进队一次,出队一次,队列中最多不会超过 n 个点,故渐进空间复杂度为 O(n)。