文章目录
碎碎念
周末这两天偷偷划水了咳咳,不过终于是进城吃上心心念念的寿司郎嘻嘻嘻。昨天本来是想来上工的但突然就电池急速掉电整个人无力了,遂在家充电。对了,昨天还第一次尝试去俱乐部打那种拼场的羽毛球,很爽啊很爽啊,感觉大家都很厉害!!我得规划一下泡图书馆and打球and锻炼减肥的时间了,这个假期一定要很充实!
一、题目


二、思路和题解
1.思路
原本想的是像层序遍历那样一层一层来,左子树的就入栈,右子树的就出栈,一旦发现有不对的就直接false,否则遍历完了就true。但是那个时候还没学会层序遍历,遂放弃。
后面又想到,前面做过翻转二叉树,如果把左子树先翻转到右子树那边,然后再和原来的右子树去作比较,只要有不一样的地方就出错。这个方案应该可行,不过当时主播沉迷于递归且觉得这个方案效率很低,也没细想。
(我错了放过我这一次吧下次一定不偷懒了TT)
于是到递归!!既然是递归,那我们就要考虑递归函数怎么写了。以下思考步骤详细请见代码随想录。
首先第一步,确认递归函数的参数和返回值 。这里我们因为是对树进行递归,且主要是判断是否对称,不需要有其他数组啊数啊来记录某一个结果什么的,所以参数就是root;返回值也很好理解了,就是true和false。
然后是确定终止条件。这里我们需要分情况讨论。因为我们是判断一个二叉树是否对称,所以就不能只是单纯的比较左孩子和右孩子是否相等,这个只能在根节点的时候是有用的,再往下就不能这么做了。那要看下面的是否对称,我们要对比的就是L.left和R.right(假设L指向左节点,R指向右节点)。这里又可以再分情况来讨论我们的终止条件了:
- 当两个指针都跨过叶子节点指向null,此时返回true:

- 当其中一个指针指向节点而另一个指针已经跨过叶子节点指向null,说明不对称,返回false:

- 当两个节点的值不相等,说明不对称,返回false:

因为题目条件里有指明节点数至少是一个,因此不用考虑空树情况。以上,包含了终止条件的所有情况。
最后一步是确定单层递归逻辑。这里其实我们在上一步已经有分析了,也就是如果当前节点是root,对比L和R是否相等;如果当前节点不是root,对比L.left和R.right是否相等以及对比L.right和R.left是否相等,只要有不相等即不对称。
2.代码(递归)
cpp
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
bool isSymmetric(TreeNode* root) {
return check(root->left,root->right);
}
bool check(TreeNode* p,TreeNode* q){
// 两个都跨过叶子节点指向null
if (!p&&!q){
return true;
}
// 不是上面的情况,说明至少有一个非空,此时存在一个空/两个节点的值不相等说明不对称
if (!p||!q||p->val!=q->val){
return false;
}
//要求 L.left节点的值等于R.right节点的值 且 L.right节点的值等于R.left节点的值 才对称
return check(p->left,q->right)&&check(p->right,q->left);
}
};
算法的时间复杂度是 O(n),因为要遍历 n 个节点
空间复杂度是 O(n),空间复杂度是递归的深度,也就是跟树高度有关,最坏情况下树变成一个链表结构,高度是n。
三、其他解法(迭代)
题解里除了递归还有迭代的做法,学习学习。
参考题解在这里,迭代和递归都有清晰的图解,推荐!
我们用队列来实现,思路如下:
- 先将根节点的左右孩子都放进队列中(特殊)
- 一次取两个节点来比较值是否相等
- 将left节点的左孩子和right节点的右孩子放入队列中
- 将left节点的右孩子和right节点的左孩子放入队列中
- 重复2-4步骤,直到队列为空或发现不对称
以下是java实现的算法。(复制粘贴题解的
java
class Solution {
public boolean isSymmetric(TreeNode root) {
if(root==null || (root.left==null && root.right==null)) {
return true;
}
//用队列保存节点
LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
//将根节点的左右孩子放到队列中
queue.add(root.left);
queue.add(root.right);
while(queue.size()>0) {
//从队列中取出两个节点,再比较这两个节点
TreeNode left = queue.removeFirst();
TreeNode right = queue.removeFirst();
//如果两个节点都为空就继续循环,两者有一个为空就返回false
if(left==null && right==null) {
continue;
}
if(left==null || right==null) {
return false;
}
if(left.val!=right.val) {
return false;
}
//将左节点的左孩子, 右节点的右孩子放入队列
queue.add(left.left);
queue.add(right.right);
//将左节点的右孩子,右节点的左孩子放入队列
queue.add(left.right);
queue.add(right.left);
}
return true;
}
}
时间复杂度是 O(n),空间复杂度是 O(n)。
四、错误回顾
递归思路没想明白,以为直接对比左右孩子。