Leetcode对称二叉树算法与分析

本文深入探讨了LeetCode上的对称二叉树问题,通过递归和迭代两种方法详细解释了如何判断一棵二叉树是否对称。递归方法通过比较左右子树的镜像对称性,而迭代方法则利用队列存储节点并进行逐层比较。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

@Leetcode对称二叉树

作为一道稍有进阶的数据结构经典题,对称二叉树的使用着实费了小白笔者不少脑筋。我一直在想能不能用先序后序遍历的方法解决,即在一棵树上做出判断,然而实际上解法并非如此。卖个关子,请看题干:

给定一个二叉树,检查它是否是镜像对称的。
例如,二叉树 [1,2,2,3,4,4,3] 是对称的。
在这里插入图片描述
下面这个 [1,2,2,null,3,null,3] 则不是镜像对称的:
在这里插入图片描述
说明:
如果你可以运用递归和迭代两种方法解决这个问题,会很加分。

虽然说题目已经暗示了有两种方法解决这个问题——递归和迭代,但是笔者脑子依然是一团浆糊,先入为主的思想真是十分该死,那么到头来到底这题的递归解法应该怎么写?请看代码:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        return judge(root,root);
    }
    
    bool judge(TreeNode* t1, TreeNode* t2) {
        if(t1==NULL&&t2==NULL)
            return true;
        else if(t1==NULL||t2==NULL)
            return false;
        else 
            return (t1->val==t2->val)
            &&judge(t1->left,t2->right)
            &&judge(t1->right,t2->left);
    }
};

在这里插入图片描述
刚看到这个想法的时候,笔者确实也不得其要领,但是当你把一棵树当成两棵树来看待,这就不一样了。

要解决这棵树是否是对称的,我们首先要了解镜像对称,又称手性对称的概念。这种对称模型就像你照镜子,或者你的两只手一样,是相对另一半的反方向对称的,即在镜子里的你的右边是你的左边,在镜子里的你的左边是你的右边。
那么同理,如果要这棵树是对称的,不妨创造另外一棵在镜子里的树,只要原有的这棵树的左子树与镜像树的右子树完全相同,镜像树的左子树也与原有的树的右子树相同,并且根结点相同,说明这棵树确实是对称的。
那么总结一下就是需要满足两个条件:第一,两棵树的根结点必须相同(可以同时为空,说明是一棵空树);第二,对应方向的左子树必须与右子树完全相等(右子树与左子树完全相等)。当这两个条件同时满足的时候就可以解决问题。
与之对应的代码如上,需要注意的是,要先判断返回true的双空情况,再判断其中一个为空的情况,因为双空情况不是已经都没有子树了就是整个为空树,这两种情况是一定可得证为正确情况的,而其中一个为空,就如第二个示例,是不可能正确的。再这两种情况都不满足的时候就是比较环节了,与之前判断相同的树时类似,使用短路运算能节省很多的运算步骤和不需要的代码:如果两个结点相等,这也是必须满足的第一个条件,再进行判断接下来的递归条件,必选其一,最终得到答案。

那么还有一种迭代的方法呢?说实话,其实迭代的方法认真思考之下是更容易想到的,无非就是我开两个队列,分别存储两个子树的每一个子节点并按顺序pop比较一下,请看代码:

class Solution {
public:
    bool isSymmetric(TreeNode* root) {
        queue<TreeNode*> q1;
        queue<TreeNode*> q2;
        q1.push(root);
        q2.push(root);
        while(!q1.empty()&&!q2.empty()){
            TreeNode* t1=q1.front();
            TreeNode* t2=q2.front();
            q1.pop();
            q2.pop();
            if (t1==NULL&&t2==NULL) continue;
            if (t1==NULL||t2==NULL) return false;
            if (t1->val!=t2->val) return false;
            
            q1.push(t1->left);
            q2.push(t2->right);
            q1.push(t1->right);
            q2.push(t2->left);
        }
        return true;
    }
};

在这里插入图片描述
迭代法参上!确实开了两个队列解决问题(实际上一个队列也能解决,只是开两个要明晰一些),要注意队列的定义和几个方法的使用,笔者在这上面CE了好多次,注意pop金近是出队头元素,并不能取得头元素的值。后面push的顺序一定要注意,要按照正确的比较顺序push这一层的结点才能起到比较镜像的作用。值得一提的是,最后有一个返回true可别丢了,否则正确的情况会在循环里不停地continue出不来,那是真的很尴尬。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值