剑指Offer:58 判断是不是对称的二叉树

第一次自己做,思路出现了问题:对称二叉树不是一棵树的左右子节点相等,而是反转二叉树之后和原二叉树一样!

class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot)
    {
        if(!pRoot) return false;
        bool flag = true;
        postorder(pRoot, flag);
        
        return flag;
    }
    
    void postorder(TreeNode* pRoot, bool& flag) {
        if(!pRoot) return;
        //if( (pRoot->left || pRoot->right) && (pRoot->left && pRoot->left) ) //逻辑异或,C++中没有对应的运算符
        if( (pRoot->left == nullptr)^(pRoot->right == nullptr) || 
           (pRoot->left && pRoot->right && pRoot->left->val!=pRoot->right->val) )
        {
            flag = false;
            return;
        }
        if(flag && pRoot->left) postorder(pRoot->left, flag);
        if(flag && pRoot->right) postorder(pRoot->right, flag);
    }
};

在看了书上的解题思路,扫了一眼代码之后,自己实现的程序,出现的问题:

1、递归时,只加 flag 会造成程序错误:这是显然的,没有判断pRoot1,pRoot2 就对它们取子节点,如果pRoot1/2为空则会出现错误。报错比较奇怪,是栈溢出,递归调用不会无穷递归下去的,肯定会到叶子节点出现上述的“取空节点的子节点”的错误。

2、if 条件中加入类似 pRoot->left 条件也不对,如果一个节点只有左子树,无右子树,比如[866577],会因为不进行递归,提前返回导致错误的返回true。因为先序遍历递归写法的惯性会让人习惯的写上 pRoot1->left 形式的判断。

3、正确的做法是,if 条件中加入 flag一旦出现 false 就返回,加入pRoot1,pRoot2判断不为空再进行递归。

4、一个小点:空树返回true

class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot)
    {
        if(!pRoot) return true;
        bool flag = true;
        biTraversal(pRoot, pRoot, flag);
        return flag;
    }
    
    //对一棵树同时进行先序遍历和对称后的先序遍历
    void biTraversal(TreeNode* pRoot1, TreeNode* pRoot2, bool& flag) {
        if((!pRoot1 && !pRoot2) || (pRoot1 && pRoot2 && pRoot1->val==pRoot2->val)) {
            flag = true;
        }
        else {
            flag = false;
        }
        
        //if(flag && pRoot1->left && pRoot2->right) biTraversal(pRoot1->left, pRoot2->right, flag);
        //if(flag && pRoot1->right && pRoot2->left) biTraversal(pRoot1->right, pRoot2->left, flag);
        if(flag && pRoot1 && pRoot2) biTraversal(pRoot1->left, pRoot2->right, flag);
        if(flag && pRoot1 && pRoot2) biTraversal(pRoot1->right, pRoot2->left, flag);
    }
};

书上的代码写法,比我自己写的要优雅很多:

之前被迫引入flag变量,就是因为不知道怎么合理的设置return:在这里不需要加上“ == ”时return true,实际上加上就是错的,只有遍历完整棵树没有出现过false才可以return true。书上的代码遇到了false也会不再继续递归而是开始向上返回。

class Solution {
public:
    bool isSymmetrical(TreeNode* pRoot)
    {
        return biTraversal(pRoot, pRoot);
    }
    
    //对一棵树同时进行先序遍历和对称后的先序遍历
    bool biTraversal(TreeNode* pRoot1, TreeNode* pRoot2) {
        if (pRoot1==nullptr && pRoot2==nullptr) return true; //两个都为nullptr
        if (pRoot1==nullptr || pRoot2==nullptr) return false; //只有一个为nullptr
        if (pRoot1->val != pRoot2->val) return false;
        //之前被迫引入flag变量,就是因为不知道怎么合理的设置return:
        //在这里不需要加上 == 时return true,实际上加上就是错的,只有遍历完整棵树才可以return true
        return biTraversal(pRoot1->left, pRoot2->right) && biTraversal(pRoot1->right, pRoot2->left); 
    }
};
发布了97 篇原创文章 · 获赞 11 · 访问量 2466

猜你喜欢

转载自blog.csdn.net/chengda321/article/details/104223816