当前位置: 首页 > news >正文

hot100_101. 对称二叉树

hot100_101. 对称二叉树

  • 思路
    • 方法一:递归
    • 迭代

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

示例 1:
在这里插入图片描述
输入:root = [1,2,2,3,4,4,3]
输出:true
示例 2:
在这里插入图片描述
输入:root = [1,2,2,null,3,null,3]
输出:false

思路

方法一:递归

如果一个树的左子树与右子树镜像对称,那么这个树是对称的。因此,该问题可以转化为:两个树在什么情况下互为镜像?如果同时满足下面的条件,两个树互为镜像:

1.它们的两个根结点具有相同的值
2.每个树的右子树都与另一个树的左子树镜像对称

我们可以实现这样一个递归函数,通过「同步移动」两个指针的方法来遍历这棵树,p 指针和 q 指针一开始都指向这棵树的根,随后 p 右移时,q 左移,p 左移时,q 右移。每次检查当前 p 和 q 节点的值是否相等,如果相等再判断左右子树是否对称。


class Solution {
    public boolean isSymmetric(TreeNode root) {
        return check(root.left,root.right);
    }
    
    public boolean check(TreeNode q,TreeNode p) {
        if(q==null && p==null){
            return true;
        }
        //已经排除了q==null && p==null , 剩下的可能是 两个不会同时为null,但只要一个为null就false
        if(q==null || p==null){
            return false;
        }
        return q.val==p.val && check(q.right,p.left) && check(q.left,p.right);
    }
}

迭代

首先我们引入一个队列,这是把递归程序改写成迭代程序的常用方法。
初始化时我们把根节点入队两次。每次提取两个结点并比较它们的值(队列中每两个连续的结点应该是相等的,而且它们的子树互为镜像),然后将两个结点的左右子结点按相反的顺序插入队列中。
当队列为空时,或者我们检测到树不对称(即从队列中取出两个不相等的连续结点)时,该算法结束。


class Solution {
    public boolean isSymmetric(TreeNode root) {
        return check(root,root);
    }
    public boolean check(TreeNode u,TreeNode v){
        Queue<TreeNode> q = new LinkedList<TreeNode>();
        q.offer(u);
        q.offer(v);
        while(!q.isEmpty()){
            u = q.poll();
            v = q.poll();
            if(u==null && v==null){
                continue;
            }
            if(v==null || u==null || (u.val != v.val)){
                return false;
            }

            q.offer(u.left);
            q.offer(v.right);

            q.offer(u.right);
            q.offer(v.left);
        }
        return true;
    }
}

在逻辑表达式中,if(v == null || u == null || (u.val != v.val)) 和 if((u.val != v.val) || v == null || u == null) 在功能上是等价的,因为逻辑或运算符 || 是可交换的,即 A || B 和 B || A 的结果是相同的。然而,它们在代码的可读性和执行顺序上可能有所不同。

  1. 逻辑功能上的等价性
    从逻辑上讲,这两个表达式是等价的。它们都检查以下条件:
    v 是否为 null
    u 是否为 null
    如果 u 和 v 都不为 null,则检查 u.val 是否不等于 v.val
    只要任意一个条件为 true,整个表达式的结果就是 true,进而触发 if 语句中的代码块。
  2. 执行顺序上的差异
    虽然逻辑上等价,但实际执行顺序可能会受到 短路逻辑(Short-circuiting) 的影响。在 Java 中,|| 是短路逻辑运算符,即如果前面的条件已经能够确定整个表达式的结果,后面的条件就不会被计算。
    第一种写法:
    java复制
    if(v == null || u == null || (u.val != v.val))
    首先检查 v == null:
    如果 v == null 为 true,整个表达式直接返回 true,不会继续检查后面的条件。
    如果 v != null,则检查 u == null:
    如果 u == null 为 true,整个表达式返回 true,不会继续检查后面的条件。
    如果 u != null,则检查 u.val != v.val。
    第二种写法:
    java复制
    if((u.val != v.val) || v == null || u == null)
    首先检查 u.val != v.val:
    如果 u.val != v.val 为 true,整个表达式直接返回 true,不会继续检查后面的条件。
    如果 u.val == v.val,则检查 v == null:
    如果 v == null 为 true,整个表达式返回 true,不会继续检查后面的条件。
    如果 v != null,则检查 u == null。
  3. 可读性和潜在问题
    虽然逻辑上等价,但第一种写法更符合常见的编程习惯,尤其是处理可能为 null 的对象时:
    安全性:第一种写法先检查 v 和 u 是否为 null,避免了在 u 或 v 为 null 时直接访问 u.val 或 v.val,从而避免了潜在的 NullPointerException。
    可读性:第一种写法更清晰地表达了意图,即先检查 null 条件,再检查值是否相等。
  4. 总结
    虽然逻辑上等价,但两种写法在执行顺序和可读性上有差异。推荐使用第一种写法:
    java复制
    if(v == null || u == null || (u.val != v.val))
    这种写法更安全,也更符合常见的编程习惯,能够有效避免 NullPointerException,并且逻辑更清晰。

相关文章:

  • 国家队出手!DeepSeek上线国家超算互联网平台!
  • 使用docker compose启动postgres并设置时区
  • 力扣100. 相同的树(利用分解思想解决)
  • 相机与激光雷达联合标定综述
  • 网络安全 | 什么是网络安全?
  • Vue2/Vue3生命周期对比
  • 第十五天 学习并实践HarmonyOS应用的基本结构、页面导航和状态管理
  • C++:构造函数,static成员,友元,内部类
  • 指标+大模型,构建更全、更准、更快的数据分析体验
  • Vue 2 + Webpack 项目中集成 ESLint 和 Prettier
  • 深入浅出理解HBase:大数据时代的“超级仓库”
  • 【大疆无人机地图测绘技术学习:高精度、高效率的全流程解决方案】
  • vue.js之虚拟 DOM
  • 生成对抗网络(GAN)的“对抗“过程解析:从图像合成到药物发现的跨领域应用
  • SpringMVC学习使用
  • 基于Spring Boot的视频点播系统设计与实现(LW+源码+讲解)
  • vue和Django快速创建项目
  • 计算机网络-MPLS基础概念
  • 堡垒机调用xshell 无反应
  • 代码随想录算法【Day45】
  • 第四届长三角国际应急博览会开幕,超3000件前沿装备技术亮相
  • 支持企业增强战略敏捷更好发展,上海市领导密集走访外贸外资企业
  • 人民日报钟声:通过平等对话协商解决分歧的重要一步
  • 国产水陆两栖大飞机AG600批产首架机完成总装下线
  • “应急侠”上线,应急管理部正式发布应急科普IP形象
  • 中美经贸高层会谈11日在日内瓦将继续进行