给「代码随想录」一个星标吧!

又是一道“简单题”?

101. 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

思路

「首先想清楚,判断对称二叉树要比较的是哪两个节点,要比较的可不是左右节点!」

对于二叉树是否对称,要比较的是根节点的左子树与右子树是不是相互翻转的,理解这一点就知道了「其实我们要比较的是两个树(这两个树是根节点的左右子树)」,所以在递归遍历的过程中,也是要同时遍历两棵树。

那么如果比较呢?

比较的是两个子树的里侧和外侧的元素是否相等。如图所示:

那么遍历的顺序应该是什么样的呢?

本题遍历只能是“后序遍历”,因为我们要通过递归函数的返回值来判断两个子树的内侧节点和外侧节点是否相等。

「正是因为要遍历两棵树而且要比较内侧和外侧节点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。」

但都可以理解算是后序遍历,尽管已经不是严格上在一个树上进行遍历的后序遍历了。

其实后序也可以理解为是一种回溯,当然这是题外话,讲回溯的时候会重点讲的。

说到这大家可能感觉我有点啰嗦,哪有这么多道理,上来就干就完事了。别急,我说的这些在下面的代码讲解中都有身影。

那么我们先来看看递归法的代码应该怎么写。

递归法

递归三部曲

  1. 确定递归函数的参数和返回值

因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。

返回值自然是bool类型。

代码如下:

bool compare(TreeNode* left, TreeNode* right)
  1. 确定终止条件

要比较两个节点数值相不相同,首先要把两个节点为空的情况弄清楚!否则后面比较数值的时候就会操作空指针了。

节点为空的情况有:(「注意我们比较的其实不是左孩子和右孩子,所以如下我称之为左节点右节点」)

  • 左节点为空,右节点不为空,不对称,return false
  • 左不为空,右为空,不对称 return  false
  • 左右都为空,对称,返回true

此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:

  • 左右都不为空,比较节点数值,不相同就return false

此时左右节点不为空,且数值也不相同的情况我们也处理了。

代码如下:

if (left == NULL && right != NULL) return false;else if (left != NULL && right == NULL) return false;else if (left == NULL && right == NULL) return true; else if (left->val != right->val) return false; // 注意这里我没有使用else

注意上面最后一种情况,我没有使用else,而是elseif, 因为我们把以上情况都排除之后,剩下的就是 左右节点都不为空,且数值相同的情况。

  1. 确定单层递归的逻辑

此时才进入单层递归的逻辑,单层递归的逻辑就是处理 右节点都不为空,且数值相同的情况。

  • 比较二叉树外侧是否对称:传入的是左节点的左孩子,右节点的右孩子。
  • 比较内测是否对称,传入左节点的右孩子,右节点的左孩子。
  • 如果左右都对称就返回true ,有一侧不对称就返回false 。

代码如下:

bool outside = compare(left->left, right->right);   // 左子树:左、 右子树:右bool inside = compare(left->right, right->left);    // 左子树:右、 右子树:左bool isSame = outside && inside;                    // 左子树:中、 右子树:中(逻辑处理)return isSame;

如上代码中,我们可以看出使用的遍历方式,左子树左右中,右子树右左中,所以我把这个遍历顺序也称之为“后序遍历”(尽管不是严格的后序遍历)。

最后递归的C++整体代码如下:

class Solution {public:    bool compare(TreeNode* left, TreeNode* right) {        // 首先排除空节点的情况        if (left == NULL && right != NULL) return false;        else if (left != NULL && right == NULL) return false;        else if (left == NULL && right == NULL) return true;        // 排除了空节点,再排除数值不相同的情况        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;                    // 左子树:中、 右子树:中 (逻辑处理)        return isSame;

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

「我给出的代码并不简洁,但是把每一步判断的逻辑都清楚的描绘出来了。」

如果上来就看网上各种简洁的代码,看起来真的很简单,但是很多逻辑都掩盖掉了,而题解可能也没有把掩盖掉的逻辑说清楚。

「盲目的照着抄,结果就是:发现这是一道“简单题”,稀里糊涂的就过了,但是真正的每一步判断逻辑未必想到清楚。」

当然我可以把如上代码整理如下:

class Solution {public:    bool compare(TreeNode* left, TreeNode* right) {        if (left == NULL && right != NULL) return false;        else if (left != NULL && right == NULL) return false;        else if (left == NULL && right == NULL) return true;        else if (left->val != right->val) return false;        else return compare(left->left, right->right) && compare(left->right, right->left);

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

「这个代码就很简洁了,但隐藏了很多逻辑,条理不清晰,而且递归三部曲,在这里完全体现不出来。」

「所以建议大家做题的时候,一定要想清楚逻辑,每一步做什么。把道题目所有情况想到位,相应的代码写出来之后,再去追求简洁代码的效果。」

迭代法

这道题目我们也可以使用迭代法,但要注意,这里的迭代法可不是前中后序的迭代写法,因为本题的本质是判断两个树是否是相互翻转的,其实已经不是所谓二叉树遍历的前中后序的关系了。

这里我们可以使用队列来比较两个树(根节点的左右子树)是否相互翻转,(「注意这不是层序遍历」)

使用队列

通过队列来判断根节点的左子树和右子树的内侧和外侧是否相等,如动画所示:

如下的条件判断和递归的逻辑是一样的。

代码如下:

class Solution {public:    bool isSymmetric(TreeNode* root) {        if (root == NULL) return true;        queue 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;            }            // 左右一个节点不为空,或者都不为空但数值不相同,返回falseif ((!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 Solution {public:    bool isSymmetric(TreeNode* root) {        if (root == NULL) return true;        stack 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;            }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;    }};

总结

这次我们又深度剖析了一道二叉树的“简单题”,大家会发现,真正的把题目搞清楚其实并不简单,leetcode上accept了和真正掌握了还是有距离的。

我们介绍了递归法和迭代法,递归依然通过递归三部曲来解决了这道题目,如果只看精简的代码根本看不出来递归三部曲是如果解题的。

在迭代法中我们使用了队列,需要注意的是这不是层序遍历,而且仅仅通过一个容器来成对的存放我们要比较的元素,知道这一本质之后就发现:用队列,用栈,甚至用数组,都是可以的。

如果已经做过这道题目的同学,读完文章可以再去看看这道题目,思考一下,会有不一样的发现!

在留言区留下你的思路吧!

-------end-------

我将算法学习相关的资料已经整理到了Github :https://github.com/youngyangyang04/leetcode-master,里面还有leetcode刷题攻略、各个类型经典题目刷题顺序、思维导图看一看一定会有所收获,如果给你有帮助给一个star支持一下吧!

另外因为公众号改版,时间线被打乱,一些精彩文章大家可能错过了。如果感觉这里的文章对你有帮助,赶紧给「代码随想录」加一个星标吧,方便第一时间阅读文章往期精彩回顾本周小结!(二叉树)二叉树:你真的会翻转二叉树么?二叉树:层序遍历登场!二叉树:前中后序迭代方式的写法就不能统一一下么?二叉树:听说递归能做的,栈也能做!二叉树:一入递归深似海,从此offer是路人关于二叉树,你该了解这些!「代码随想录」期待你的关注!

每天8:35准时推送一道经典算法题目,推送的每道题目都不是孤立的,而是由浅入深,环环相扣,帮你梳理算法知识脉络,轻松学算法!

刷题可以加我微信!右边为个人微信,添加时备注:「简单自我介绍」+「组队刷题」我就知道你[在看]

判断是否是完全二叉树_二叉树:我对称么?相关推荐

  1. 判断是否是完全二叉树_【数据结构】二叉树高频考试题目【代码模板】!

    本文来自公众号程序员小乐(study_tech) 作者:IOExceptioner 编辑:www.jianshu.com/p/0190985635eb 先上二叉树的数据结构: class TreeNo ...

  2. 二叉树的进阶操作---(求二叉树中所有结点个数,求叶子结点个数,求第k层结点个数;在二叉树中查找某一结点;层序遍历;判断是否为完全二叉树)

    typedef struct TreeNode {struct TreeNode *left;struct TreeNode *right;char val; }TreeNode;typedef st ...

  3. Php二叉树对称,PHP如何实现判断二叉树是否对称

    本文主要介绍了PHP实现判断二叉树是否对称的方法,涉及php递归二叉树判断节点的相关操作技巧,需要的朋友可以参考下,希望能帮助到大家. 问题 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果 ...

  4. 常考数据结构与算法:判断二叉树是否对称(迭代法,递归法)

    给定一棵二叉树,判断琪是否是自身的镜像(即:是否对称) 例如:下面这棵二叉树是对称的      1     /  \   2    2  / \    / \ 3 4  4  3 下面这棵二叉树不对称 ...

  5. php 二叉树判断节点的位置,PHP实现判断二叉树是否对称的方法

    本文实例讲述了PHP实现判断二叉树是否对称的方法.分享给大家供大家参考,具体如下: 问题 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的. ...

  6. 剑指offer之中判断二叉树是不是对称二叉树(递归和非递归实现)

    1 问题 判断二叉树是不是对称(递归和非递归实现) 如下二叉树,就是对称的二叉树 23 3 1 4 4 1 如下二叉树,就是非对称的二叉树 23 3 1 4 4 2 2 代码实现 #include & ...

  7. 牛客题霸 [判断二叉树是否对称] C++题解/答案

    [牛客题霸 [判断二叉树是否对称] C++题解/答案](https://www.nowcoder.com/practice/1b0b7f371eae4204bc4a7570c84c2de1?tpId= ...

  8. 判断二叉树是否对称的代码

    思路:要判断一颗二叉树是否对称,要判断一下几点,可以用递归来实现: 判断一颗二叉树是不是对称的,等价于判断其左右子树是不是镜像对称的 判断镜对称像即判断对称的位置上的元素是不是相等 两个节点A和B对称 ...

  9. 对称二叉树c++_二叉树:我对称么?

    给「代码随想录」一个星标吧! ❝ 又是一道"简单题"? ❞ 101. 对称二叉树 给定一个二叉树,检查它是否是镜像对称的. 思路 「首先想清楚,判断对称二叉树要比较的是哪两个节点, ...

  10. 判断一颗二叉树是否对称

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u012311410/article/details/71108475 1.题目描述 请实现一个函数, ...

最新文章

  1. qu.la网站上的小说爬取
  2. HTML5原生拖拽/拖放 Drag Drop 详解
  3. Qt5 和 Qt4 的一些改动和不同
  4. 嵌入式linux基础知识累积
  5. Angular input控件的click事件表达式如何被转换成JavaScript函数
  6. Docker 方式安装 zipkin (linux 、阿里云ECS上安装)
  7. js call(),apply(),对象冒充,改变变量作用域
  8. stn算子_深度学习常用算子(二)
  9. 比亚迪拟发债100亿元补充营运资金偿还借款
  10. java 弹窗选择_如何在java中点击button弹出一个选择框
  11. 如何下载Chrome历史版本
  12. NetXray使用说明之(6)----捕捉oicq message报文 (转)
  13. 限制input输入框的输入字符个数,区别中英文字符
  14. Clouda 之我见
  15. 去掉WebView中的白色背景
  16. 前端如何设置浏览器网页标签页前的小图标favicon.ico
  17. ADIS16488与单片机SPI通信返回0xFFFF的问题解决方法
  18. Apex开发人员指南
  19. 【vs2019】调试介绍
  20. 计算机学院请假管理系统,《计算机学院在校学生离校请销假管理暂行规定》

热门文章

  1. linux在多核处理器上的负载均衡原理(2)
  2. L1- 009——016
  3. scala字符串变量替换
  4. java操作mysql实例 让代码跑起来
  5. 空头平仓什么意思_什么是白糖期货期权仿真交易套利机会?
  6. aes解密流程图_AES加密算法详解
  7. md5是什么_全民小视频视频修改md5有什么用6
  8. 电脑教程从入门到精通_【电路仿真】视频教程资料包,proteus入门到精通+实例教程+软件,免费下载!...
  9. abb工业机器人电压不稳_ABB工业机器人常见故障及解决方法,想要提升自己的就赶紧保存下来吧...
  10. 图:用PPT为湖北黄石某电视台及其有线电视定制的知识竞赛题库