理解何为对称
如下图所示,以根节点做中轴,沿着中轴线翻转,左边的子树结构与右边完全一样,并且对应的每一个节点得都一样
图片说明
可以同过left、right两个指针在树上移动,模拟判断树是否对称;
图片说明

题解一:递归
主要思路:使用递归函数,在递归函数里面传入两个指针,充当上图中得left、right指针;
思考点:
递归函数返回值:
是:true,不是:false

递归函数的停止条件:
1、left、right指针指向的节点必须同时为空,返回true
2、left、right指针指向的节点不同时为空,返回false
3、left、right指针指向的节点都不为空,值不相同,返回false;
4、left、right指针指向的节点都不为空,值相同,递归调用下一层,判断是否上足上述3点要求;

从上图模拟中可以看出我们的递归调用方案:
判断下一层是否满足对称时,传入的left、right指针不在同一侧,即 f(Lroot->left,Rroot->right)和 f(Lroot->right,Rroot->left)

复杂度分析:
时间复杂度:O(n),n为二叉树的节点
空间复杂度:O(n),递归栈深度

实现如下:

/**
 * struct TreeNode {
 *    int val;
 *    struct TreeNode *left;
 *    struct TreeNode *right;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param root TreeNode类 
     * @return bool布尔型
     */
    bool f(TreeNode* Lroot, TreeNode* Rroot) {
    if (!Lroot && !Rroot)return true;//left、right指针指向的节点必须同时为空,返回true
    if (!Lroot || !Rroot)return false;//left、right指针指向的节点不同时为空,返回false
    if (Lroot->val != Rroot->val)return false;//left、right指针指向的节点都不为空,值不相同,返回false;
    return f(Lroot->left, Rroot->right) && f(Lroot->right, Rroot->left);//left、right指针指向的节点都不为空,值相同,递归调用下一层,判断是否上足上述3点要求;

}

bool isSymmetric(TreeNode* root) {
    // write code here
    return f(root, root);
}
};

题解二:利用队列
主要思路:
1、将left、right指针指向对称的两个节点值存入队列,如果树结构不一致,直接返回fale,将一层的对称的节点值相邻存放至队列中;
参照上图模拟情况的四个步骤,队列中的存放元素如下图所示(根节点特判单独处理):
图片说明
2、每次从队列中取两个值,判断是否相等,以此来判断是否对称;
3、遍历完所有的节点,全都符合对称定义,即返回true,否则返回false;

复杂度分析:
时间复杂度:O(n),n为二叉树的节点

实现如下:

/**
 * struct TreeNode {
 *    int val;
 *    struct TreeNode *left;
 *    struct TreeNode *right;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param root TreeNode类 
     * @return bool布尔型
     */
bool isSymmetric(TreeNode* root) {
    // write code here
    if (root == NULL) return true;//特判根节点;
        queue<TreeNode*> q;
        q.push(root->left);   // 将左子树头结点加入队列
        q.push(root->right);  // 将右子树头结点加入队列
        while (!q.empty()) {  // 接下来就要判断这这两个树是否相互翻转
            TreeNode* leftNode = q.front(); 
            q.pop();//出队    
            TreeNode* rightNode = q.front(); 
            q.pop();//出队
            if (!leftNode && !rightNode) {  //left、right指针指向的节点同时为空,满足对称条件
                continue;
            }
            //left、right指针指向的节点不同时为空或者left、right指针指向的节点都不为空,值不相同,直接返回false
            if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) { 
                return false;
            }
            //将相互对称的节点放在相邻的位置
            //从逻辑上看,将下一层的对称的节点放在一起;
            q.push(leftNode->left);   // 加入左节点左孩子
            q.push(rightNode->right); // 加入右节点右孩子
            q.push(leftNode->right);  // 加入左节点右孩子
            q.push(rightNode->left);  // 加入右节点左孩子
        }
        return true;
    }
};

题解三:利用栈
思路与题解二差不多,但是逻辑上类似于深度搜索,将两个字节的对称路径上的节点判断是否值相等;
实现如下:

/**
 * struct TreeNode {
 *    int val;
 *    struct TreeNode *left;
 *    struct TreeNode *right;
 * };
 */

class Solution {
public:
    /**
     * 
     * @param root TreeNode类 
     * @return bool布尔型
     */
bool isSymmetric(TreeNode* root) {
    // write code here
    if (root == NULL) return true;//特判根节点;
        stack<TreeNode*> s;
        s.push(root->left);   // 将左子树头结点加入栈
        s.push(root->right);  // 将右子树头结点加入栈
        while (!s.empty()) {  // 接下来就要判断这这两个树是否相互翻转
            TreeNode* leftNode = s.top(); 
            s.pop();//出栈    
            TreeNode* rightNode = s.top(); 
            s.pop();//出栈
            if (!leftNode && !rightNode) {  //left、right指针指向的节点同时为空,满足对称条件
                continue;
            }
            //left、right指针指向的节点不同时为空或者left、right指针指向的节点都不为空,值不相同,直接返回false
            if ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) { 
                return false;
            }
            //将相互对称的节点放在相邻的位置
            s.push(leftNode->left);   // 加入左节点左孩子
            s.push(rightNode->right); // 加入右节点右孩子
            s.push(leftNode->right);  // 加入左节点右孩子
            s.push(rightNode->left);  // 加入右节点左孩子
        }
        return true;
    }
};