101. 对称二叉树

题目描述:

给你一个二叉树的根节点 root , 检查它是否轴对称。

示例 1:

101. 对称二叉树_第1张图片


输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:

101. 对称二叉树_第2张图片


输入:root = [1,2,2,null,3,null,3]
输出:false

提示:

树中节点数目在范围 [1, 1000] 内
-100 <= Node.val <= 100
 

进阶:你可以运用递归和迭代两种方法解决这个问题吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/symmetric-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

分析:

        这道题看提示有两种做法,然而我一种都不会。。。二叉树的递归一直是弱点。

  一、迭代       

        这是层序遍历的变种,整体上按照层来压入新节点,从头部取出了老节点。

        队列跟层序遍历有关,栈跟前序遍历和中序遍历有关

        迭代看了看题解,大致知道是什么样的流程了。核心就是用队列来将递归函数转化为迭代算法。判断树是否为镜像对称:

        1.树的左右节点入队列

        2.队列不为空时,取出队列前两个节点

        3.比较两个节点,两节点不相等返回false。

        4.两节点相等,比较他们的左右节点按照相反的顺序入队列

        5.重复执行2-5,直到队列为空或者返回了false

        6.队列为空,说明该树是镜像对称,返回true

题解如下:

https://leetcode-cn.com/problems/symmetric-tree/solution/dui-cheng-er-cha-shu-by-leetcode-solution/

代码如下:

/**
 * 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:
    // 递归算法转为迭代算法,常见的方法就是使用队列进行转换
    queue q;
    bool isSymmetric(TreeNode* root) {
        // 树为空直接返回false
        if(root==NULL) return false;
        // 树的左右节点添加到队列中
        q.push(root->left);
        q.push(root->right);
        // 进行判断
        return f();
    }
    // f函数用来判断根节点的子树是否为镜像
    bool f()
    {
        // l和r分别用来存储队列中两个相邻的节点
        TreeNode *l=NULL;
        TreeNode *r=NULL;
        // 队列不为空,进行循环
        while(!q.empty())
        {   
            // 如果队列不为空,取出队列首节点,赋给l,之后删除该节点
            if(!q.empty()) 
            {
                l=q.front();
                q.pop();
            }
            // 如果队列不为空,取出队列首节点,赋给r,之后删除该节点
            if(!q.empty()) 
            {
                r=q.front();
                q.pop();
            }
            // 如果l和r为NULL,说明是镜像,进行下一次循环
            if(!l&&!r) continue;
            // 如果l和r只有一个为NULL,则说明不是镜像,返回false
            if(!l||!r) return false;
            // 如果l和r不相等,说明不是镜像,返回false
            if(l->val!=r->val) return false;
            else
            {
                // 如果l和r相等,说明截止到目前为止,该树还是镜像对称的
                // 接下来判断l和r节点的左右子树
                // l的左子树和r的右子树对称,因此加入队列
                q.push(l->left);
                q.push(r->right);
                // l的右子树和r的左子树对称,因此加入队列
                q.push(l->right);
                q.push(r->left);
            }
        }
        // 队列为空,说明遍历完整个树,没有发现不对称的情况,因此返回true
        return true;
        
    }
};

二、递归

        递归不单单只有前序,中序和后序,还有很多的变种,要明白递归函数是干什么用的,它的功能是什么。比如这道题,如果定义递归函数f的功能为:判断左/右子树是否为镜像对称。那么就无法继续进行下去,因为左右子树镜像对称,并不能说明这两个子树相互镜像对称。例如,二叉树序列1,2,2,3,3,4,4,左子树2,3,3是镜像对称,右子树2,4,4也是镜像对称,但是左右子树并不镜像对称。

        因此,必须改变函数f的功能。f的功能为先判断两节点是否镜像对称,再通过递归函数判断两个节点的左右子节点是否镜像对称。如果两个节点的左右子节点也镜像对称,则该二叉树镜像对称。

代码如下:

/**
 * 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) {
        // 判断root的左右节点是否对称
        return f(root->left,root->right);
    }
    // 函数f,用来判断两个节点是否为镜像对称
    bool f(TreeNode* left,TreeNode* right)
    {
        // 两节点为NULL,镜像对称,返回true
        if(!left&&!right) return true;
        // 其中一个为NULL,不镜像对称,返回false
        if(!left||!right) return false;
        // 两节点不相等,不镜像对称,返回false
        if(left->val!=right->val) return false;
        // 两节点镜像对称,起决定作用的,只剩下两节点的左右节点是否镜像对称,如果也对称,则返回true
        return f(left->left,right->right)&&f(left->right,right->left);
    }
};

你可能感兴趣的:(leetcode,算法,leetcode,动态规划)