101. 对称二叉树
题目链接:
给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3]
是对称的。
1
/ \
2 2
/ \ / \
3 4 4 3
但是下面这个 [1,2,2,null,3,null,3]
则不是镜像对称的:
1
/ \
2 2
\ \
3 3
你可以运用递归和迭代两种方法解决这个问题吗?
题解
思路:根据题意可知,判断一棵树是不是镜像对称的,就是对比根节点的“左子树”和“右子树”,镜像对称就是要求“左子树翻转以后和右子树一模一样”。对左子树可以采取左右中的遍历方式,而对右子树采取右左中的遍历方式。
代码(C++):
//方法一:递归(1.确定递归函数的参数和返回值;2.确定终止条件;3.确定单层递归的逻辑) class Solution1 { public: bool isSymmetric(TreeNode* root) { if (root == nullptr) return true; return compare(root->left, root->right); } bool compare(TreeNode* node1, TreeNode* node2) { if (node1 == nullptr && node2 != nullptr) return false; else if (node1 != nullptr && node2 == nullptr) return false; else if (node1 == nullptr && node2 == nullptr) return true; else if (node1->val != node2->val) return false; else if (node1->val == node2->val) {//其实这里的if语句写不写都可,因为前面把“这种情况”以外的所有情况都列举出来了 bool result1 = compare(node1->left, node2->right);//左子树:左;右子树:右 bool result2 = compare(node1->right, node2->left);//左子树:右;右子树:左 bool result = result1 && result2;//左子树:中;右子树:中(逻辑处理) return result; } return false; } }; //方法二:迭代 //使用队列实现 class Solution2 { public: bool isSymmetric(TreeNode* root) { if (root == nullptr) return true; if (root->left == nullptr && root->right == nullptr) return true; else if (root->left == nullptr || root->right == nullptr) return false; //以上排除了根节点左右孩子都为空,根节点左右孩子其中一个为空的情况,剩下的就是左右孩子都不为空的情况 queue<TreeNode*> que; que.push(root->left); que.push(root->right); while (!que.empty()) { TreeNode* node1 = que.front(); que.pop(); TreeNode* node2 = que.front(); que.pop(); if (node1->val != node2->val) return false; if (node1->left == nullptr && node2->right == nullptr); else if (node1->left == nullptr || node2->right == nullptr) return false; else { que.push(node1->left); que.push(node2->right); } if (node1->right == nullptr && node2->left == nullptr); else if (node1->right == nullptr || node2->left == nullptr) return false; else { que.push(node1->right); que.push(node2->left); } } return true; } }; //迭代 //使用队列实现,代码更简洁 class Solution3 { public: bool isSymmetric(TreeNode* root) { if (root == nullptr) return true; queue<TreeNode*> que; que.push(root->left); que.push(root->right); while (!que.empty()) { TreeNode* node1 = que.front(); que.pop(); TreeNode* node2 = que.front(); que.pop(); if (node1 != nullptr && node2 == nullptr) return false; else if (node1 == nullptr && node2 != nullptr) return false; else if (node1 == nullptr && node2 == nullptr); else if (node1->val != node2->val) return false; else if (node1->val == node2->val) { //其实这里的if语句写不写都可,因为前面把“这种情况”以外的所有情况都列举出来了 que.push(node1->left); que.push(node2->right); que.push(node1->right); que.push(node2->left); } } return true; } }; //迭代 //使用“栈”实现,把左右两个子树要比较的元素顺序放进一个容器,然后成对成对的取出来进行比较,只要将上面使用“队列”的方法中的队列改成栈即可,其余的代码不用改变 //这里给出更简洁的代码 class Solution4 { public: bool isSymmetric(TreeNode* root) { if (root == nullptr) return true; stack<TreeNode*> sta; sta.push(root->left); sta.push(root->right); while (!sta.empty()) { TreeNode* node1 = sta.top(); sta.pop(); TreeNode* node2 = sta.top(); sta.pop(); if (!node1 && !node2) continue; if (!node1 || !node2 || (node1->val != node2->val)) { return false; } sta.push(node1->left); sta.push(node2->right); sta.push(node1->right); sta.push(node2->left); } return true; } };
代码(Java):
//迭代
class Solution { public boolean isSymmetric(TreeNode root) { if (root == null) return true; Deque<TreeNode> que = new LinkedList<>(); que.offer(root.left); que.offer(root.right); while (!que.isEmpty()) { TreeNode node1 = que.poll(); TreeNode node2 = que.poll(); if (node1 == null && node2 == null); else if (node1 == null || node2 == null || (node1.val != node2.val)) return false; else { que.offer(node1.left); que.offer(node2.right); que.offer(node1.right); que.offer(node2.left); } } return true; } }
分析:
方法一:递归
-
时间复杂度:这里遍历了这棵树,渐进时间复杂度为O(n)。
-
空间复杂度:与递归使用的栈空间有关,这里递归层数不超过 n,故渐进空间复杂度为 O(n)。
方法二:迭代
-
时间复杂度:O(n),遍历了这棵树。
-
空间复杂度:这里用一个队列来维护节点,每个节点最多进队一次,出队一次,队列中最多不会超过 n 个点,故渐进空间复杂度为 O(n)。
参考链接