【力扣-二叉树】4、对称二叉树(101)

177 阅读3分钟

「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战

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

解析

/*
二叉树是否对称:
    即根节点的两个子树可以相互反转
    所以我们需要比较的就是两棵子树:根节点的左子树和右子树
    选择递归方法,同时遍历两棵树

    这里只能选择后续遍历:一个树的遍历是左右中,另一个树的遍历是右左中
    
递归三部曲:
    1、确定递归函数的参数与返回值
        要比较的是左右两个子树,所以参数为左右子树的节点
        返回值是比较的结果,相同就为true,否则为false
    2、确定终止条件
        要比较两个节点数值是否相同
        首先要判断两个节点是否为空
            (1)左节点为空,右节点不为空,返回 false
            (2)左节点不为空,右节点为空,返回 false
            (3)左右节点都为空,返回 true
        再判断节点非空的情况
            (1)左节点的值 == 右节点的值 , 返回 true
            (2)左节点的值 != 右节点的值 , 返回 false
    3、确定单层递归的逻辑
        单层递归的逻辑就是处理左右节点不为空,且数值相同的情况
        (1)树外侧是否对称:传入左节点的左孩子,右节点的右孩子
        (2)树内侧是否对称,传入左节点的右孩子,右节点的左孩子
        (3)如果内侧和外侧都对称,返回 true , 有一侧不对称,返回 false
*/

递归法

class Solution
{
public:
    bool isSymmetric(TreeNode *root)
    {
        if (root == NULL)
        {
            return true;
        }
        return compare(root->left, root->right);
    }

    bool compare(TreeNode *left, TreeNode *right)
    {
        // 首先排除空节点的情况
        if (left == NULL && right == NULL) // 左右节点均为空
        {
            return true;
        }
        else if (left == NULL && right != NULL) // 左节点为空,右节点非空
        {
            return false;
        }
        else if (left != NULL && right == NULL) // 左节点非空,右节点为空
        {
            return false;
        }
        // 排除数值不相同的情况
        else if (left->val != right->val)
        {
            return false;
        }

        // 下面的是 左右节点都不为空,且数值相同的情况
        // 此时递归处理,做下一层的判断
        bool outside = compare(left->left, right->right); // 左节点的左子树,右节点的右子树
        bool inside = compare(left->right, right->left);  // 左节点的右子树,右节点的左子树
        bool isSame = outside && inside;                  // 外侧和内侧都是相同则返回 true,否则返回false
        return isSame;
    }
};

迭代法(队列)

class Solution2
{
public:
    bool isSymmetric(TreeNode *root)
    {
        if (root == NULL)
        {
            return true;
        }
        queue<TreeNode *> que;
        que.push(root->left);  //根节点的 左子树入队
        que.push(root->right); //根节点的 右子树入队

        while (!que.empty())
        {
            // 左节点出队
            TreeNode *leftNode = que.front();
            que.pop();
            // 右节点出队
            TreeNode *rightNode = que.front();
            que.pop();

            // 如果左右都为空
            if (!leftNode && !rightNode)
            {
                continue;
            }
            // 如果左右节点有一个非空,或是左右节点的值不同,不对称,返回false
            else if (!leftNode || !rightNode || leftNode->val != rightNode->val)
            {
                return false;
            }

            // 外侧节点入队
            que.push(leftNode->left);   // 左节点的左孩子
            que.push(rightNode->right); // 右节点的右孩子
            // 内侧节点入队
            que.push(leftNode->right); // 左节点的右孩子
            que.push(rightNode->left); // 右节点的左孩子
        }
        return true;
    }
};

迭代法(栈)

class Solution3
{
public:
    bool isSymmetric(TreeNode *root)
    {
        if (root == NULL)
        {
            return true;
        }
        stack<TreeNode *> st;
        st.push(root->left);
        st.push(root->right);
        while (!st.empty())
        {
            TreeNode *leftNode = st.top();
            st.pop();
            TreeNode *rightNode = st.top();
            st.pop();

            if (!leftNode && !rightNode)
            {
                continue;
            }
            else if (!leftNode || !rightNode || leftNode->val != rightNode->val)
            {
                return false;
            }

            st.push(leftNode->left);
            st.push(rightNode->right);
            st.push(leftNode->right);
            st.push(rightNode->left);
        }
        return true;
    }
};