101.对称二叉树 | 递归 + 迭代

news2025/1/16 2:32:36

对称二叉树

leetcode : https://leetcode.cn/problems/symmetric-tree/

参考 对称二叉树

递归思路

首先在开始时, 一定要注意, 对称二叉树对比的并不是一个节点的左右子树, 而是两棵树, 这个很关键!

image-20230111211254708

对比时是内侧和内侧对比, 外侧和外侧对比,

递归三步 :

  1. 确定递归的参数以及返回值

    本题中需要去对比内侧和外侧节点是否对称, 所以返回值是 boolean 类型

     private boolean compare(TreeNode left, TreeNode right)
    
  2. 确定终止条件 :

    • 我们在对比两棵树是否对称时, 主要分为以下几种情况

    • 左节点为空, 右节点不为空, 不对称 (注意这里是左节点和右节点, 而不是左子树和右子树)

    • 左节点不为空, 右节点为空, 不对称

    • 左右节点都为空, 对称

    • 左右节点都不为空, 此时要比较二者的值

image-20230111211746071
 		// 终止条件 : 避免操作空指针
        // 1. 左节点为空, 右节点不为空 不对称
        if(left == null && right != null) {
            return false;
        }
        // 2. 左节点不为空, 右节点为空 不对称
        if(left != null && right == null) {
            return false;
        }
        // 3. 左节点为空, 右节点为空 对称
        if(left == null && right == null) {
            return true;
        }
  1. 确定当前层逻辑
  • 在确定了终止条件为空的情况下, 当前层的逻辑是 判断两个节点值是否相同
  • 然后分别对比两棵树的内侧和外侧的节点
  		if(left.val != right.val) {
            return false;
        }
        // 1. 对比内侧
        boolean inside = compare(left.right, right.left);
        // 2. 对比外侧
        boolean outside = compare(left.left, right.right);

        return inside && outside;

递归流程

初始状态 : 传入 left 和 right

image-20230111213511399

首先是会判断是否存在 left 或者 right 为空的情况(终止条件) , 这个也是为了防止处理空节点

然后我们要对比以 left 为根节点 和 以right 为根节点的树, 如下图所示, 这个很关键

image-20230111213710704

首先对比内侧的 :

boolean inside = compare(left.right, right.left);

image-20230111213848145

同理, 我们对比内侧其实就是对比的 left.right 和 right.left 这两棵子树是否对称

我们假设, 当前的树不再向下延伸(这棵树就这么大), 此时的逻辑是

  1. 先判断是否满足终止条件, 也就是存在 left.right 或者 right.left 为空的情况, 此时不对称, 直接就返回结果了

    boolean inside = compare(left.right, right.left);
    

    inside = false , 直接结束

  2. 假设没有到达终止条件, 先比较 left.right.val 和 right.left.val 是否相等

  3. 比较内侧和外侧的节点是否对称

  4. 最后会返回 left.right 和 right.left 这两棵树的是否对称的结果

需要补充的是, 当最后到达叶子节点时, 其实叶子节点也可以看做左右子节点都为空的树

image-20230111214540654

如上图所示, 此时他们会被下面的代码处理

// 3. 左节点为空, 右节点为空 对称
        if(left == null && right == null) {
            return true;
        }

递归代码

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        return compare(root.left, root.right);
    }

    private boolean compare(TreeNode left, TreeNode right) {
        
        // 终止条件 : 避免操作空指针
        // 1. 左节点为空, 右节点不为空 不对称
        if(left == null && right != null) {
            return false;
        }
        // 2. 左节点不为空, 右节点为空 不对称
        if(left != null && right == null) {
            return false;
        }
        // 3. 左节点为空, 右节点为空 对称
        if(left == null && right == null) {
            return true;
        }

        // 当前层的处理逻辑 : 左右子树都不为空
        if(left.val != right.val) {
            return false;
        }

        // 下一层
        // 1. 对比内侧
        boolean inside = compare(left.right, right.left);
        // 2. 对比外侧
        boolean outside = compare(left.left, right.right);

        return inside && outside;
    }

}

迭代思路

迭代思路和递归思路有一些相似, 都是外侧和外侧对比, 内侧和内侧对比 !

核心的点就是把每一层的取出来, 然后按照 内侧对内侧 和 外侧对外侧的顺序存入队列

这样的话, 每次取出栈顶的两个都是一对的

image-20230111223028579

如上图, 核心点是存入队列的时候, 存入的顺序是成对的!

因为取出来正好的成对的, 这样取出节点后, 我们只需要判断是否对称即可

  1. 左右节点都为空, 不处理, 直接跳过 (对称)
  2. 左节点为空, 右节点不为空 (不对称)
  3. 左节点不为空, 右节点为空 (不对称)
  4. 左右节点都不为空, 比较两个节点的值是否相同

迭代代码

需要注意的是 , LinkedList 是可以存储null值的, 其他的数据结构不一定支持

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public boolean isSymmetric(TreeNode root) {
        Queue<TreeNode> queue = new LinkedList<>();

        queue.add(root.left);
        queue.add(root.right);

        while(!queue.isEmpty()) {

            TreeNode left = queue.poll();
            TreeNode right = queue.poll();

            // 判断
            // 1. 左空, 右不空, 不对称
            if(left == null && right != null ) {
                return false;
            }
            // 2. 左不为空, 右为空 不对称
            if (left != null && right == null) {
                return false;
            }
            // 左右都为空, 就不处理
            if(left == null && right == null) {
                continue;
            }

            // 左右都不为空的情况, 比较二者的值
            if(left.val != right.val) {
                return false;
            }

            // 将下一层子节点添加到队列
            // 注意, 要按照对称的顺序, 外侧对外侧, 内侧对内侧
            // left.left 和 right.right
            // left.right 和 right.left
            // 外侧
            queue.add(left.left);
            queue.add(right.right);
            // 内侧
            queue.add(left.right);
            queue.add(right.left);
        }

        return true;
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/156060.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

1.1.2 了解JAVA语言

文章目录1 JAVA语言发展史2 面向对象的概念3 跨平台性4 JDK1 JAVA语言发展史 JAVA是由詹姆斯•高斯林&#xff08;James Gosling&#xff09;所创建的&#xff0c;其1977年获得了加拿大卡尔加里大学计算机科学学士学位&#xff0c;1983年 获得了美国卡内基梅隆大学计算机科学博…

4)Mybatis数据源以及事务实现

1. Mybatis数据源分为两种&#xff0c;一种直接连接数据库&#xff0c;一种使用连接池连接数据库&#xff0c;具体代码实现在包目录下 org.apache.ibatis.datasource 数据源接口&#xff1a; javax.sql.DataSource 池化数据源&#xff1a; org.apache.ibatis.datasource.…

OpenGL集锦(1)-安装与概述

目录概述&#xff46;&#xff45;&#xff44;&#xff4f;&#xff52;&#xff41;下安装编写OpenGL应用程序测试hello,world概述 OpenGL&#xff08;英语&#xff1a;Open Graphics Library&#xff0c;译名&#xff1a;开放图形库或者“开放式图形库”&#xff09;是用于…

Lichee_RV学习系列--CoreMark-Pro移植

Lichee_RV学习系列文章目录 Lichee_RV学习系列—认识Lichee Rv Dock、环境搭建和编译第一个程序 Lichee_RV学习系列—移植dhrystone 文章目录Lichee_RV学习系列文章目录一、CoreMark-Pro简介二、获取源码三、编译coremark-pro1、配置coremark-pro2、编译coremark-pro四、开发板…

各种树的总结

1.B树和B树 数据库的大量数据用什么存储&#xff1f;为什么是B树和B树&#xff1f;使用二叉树不行吗&#xff1f;先来说说他们的演变吧&#xff0c;首先如果用二叉树的话都为排好序的树查询起来是不是效率不高&#xff1f;所以此时我们提出了对树排序&#xff0c;就变成了二叉…

联想拯救者屏幕亮度无法调节,监视器和显卡驱动问题,经过多种测试

主要的问题位置 1&#xff0c;设备管理器中的监视器部分 2&#xff0c;设备管理器的显卡适配器部分 个人电脑出现这种情况的原因 自己拆一下机器加装固态&#xff0c;但这种感觉不应该导致问题。但导致这种问题的原因可能是装固态时候把电池拔了。 一些网上常说的方法 更新…

数字化转型对企业有什么意义?有哪些案例可以分享?

如何看待制造企业数字化转型&#xff1f;制造业企业数字化转型有哪些思路和案例&#xff1f; 一提到制造企业数字化转型&#xff0c;大多数人都认为&#xff0c;这是专属于大型制造企业的行为。其实不然&#xff0c;对于中小型制造企业&#xff0c;数字化转型也应该从易到难&a…

interview

1.PyTorch1.1 Conv2d1.2 dataset&#xff0c;dataloader1.3 训练pipeline1.4 梯度归零1.5 torch保存模型种类及区别2.目标检测2.1 yolo3,4,5,7区别2.2 yolo使用的loss(ciou,BCE等等)ciouBCElossL1,L2,CE,BCE2.3 图像增强2.4 IOU计算公式3.深度学习基础3.1 卷积公式4.TensorRT5.…

Niantic:未来AR重要场景,VPS众包3D地图到底是啥?

几个世纪以来&#xff0c;人们使用指南针、地图、星盘和象限仪来找路&#xff0c;而在过去二十年里&#xff0c;GPS成为了主流的定位系统&#xff0c;并且与手机结合后&#xff0c;让人们的出行越来越方便。而随着摄像头等技术发展&#xff0c;我们也开始看到视觉定位技术的崛起…

(almalinux,rockylinux,openeuler,openanolis,centos,ubuntu)云原生容器镜像漏洞trivy扫描对比

一、下载并安装trivy漏洞扫描工具 下载&#xff1a; https://github.com/aquasecurity/trivy/releases/download/v0.31.3/trivy_0.31.3_Linux-64bit.rpm 以下为centos平台的安装&#xff1a; [rootlocalhost ~]# rpm -ivh trivy_0.31.3_Linux-64bit.rpm Preparing... …

【算法刷题 DAY03】剑指offer树相关算法题总结2

JZ7 重建二叉树 描述 给定节点数为 n 的二叉树的前序遍历和中序遍历结果&#xff0c;请重建出该二叉树并返回它的头结点。 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}&#xff0c;则重建出如下图所示。 提示: 1.vin.length pre.length 2.pre 和…

CSS入门二、美化页面元素

零、文章目录 文章地址 个人博客-CSDN地址&#xff1a;https://blog.csdn.net/liyou123456789个人博客-GiteePages&#xff1a;https://bluecusliyou.gitee.io/techlearn 代码仓库地址 Gitee&#xff1a;https://gitee.com/bluecusliyou/TechLearnGithub&#xff1a;https:…

【高速数字化仪应用案例系列】虹科数字化仪在光纤领域的应用

光纤应用 光纤越来越多地应用于各种领域。它们能够以光速长距离传输信息&#xff0c;并且损耗低&#xff0c;这使它们成为大容量远程数据通信的主要媒介。因此&#xff0c;光纤网络可以在电信系统中找到&#xff0c;它们用于传输和接收的目的。它们还用于提供各种数字服务&…

Docker命令-常用命令讲解

Docker常用命令 一&#xff1a;帮助命令二&#xff1a;镜像命令1. docker images 查看所有本地的主机上的镜像2. docker search 镜像名3. docker pull 下载镜像4. docker rmi三&#xff1a;容器命令1.docker run 新建容器并启动2.从容器返回到主机&#xff1a;3.docker ps 列出…

收银软件哪家强?2023年收银软件排行榜新鲜出炉!

每家实体店都少不了收银的程序&#xff0c;每个实体店老板都离不开收银的工具。随着信息技术的发展&#xff0c;收银的工具不再只有收银机&#xff0c;更高效、更方便的收银软件&#xff0c;已经成为了零售店老板们的新宠。收银机和收银软件有什么区别&#xff1f;收银机只能对…

1.11 LED灯点亮串口解析器

LED点灯实验 一&#xff0e;电路图&#xff1a; 三极管&#xff1a; NPN类型&#xff1a; PNP类型&#xff1a; NPN类型当基极为高电平时&#xff0c;集电极和发射极导通 PNP类型当基极为低电平时&#xff0c;集电极和发射极导通 由电路图可知LED电路图中三极管为NPN类型&am…

我在CSDN的2022---2023Flag

一、加入CSDN我是在2020年12月注册的CSDN&#xff0c;大一上学期就听同学给我讲了这个软件&#xff0c;然后就下载了&#xff0c;里面确实很多优质文章&#xff0c;对于当时向我们这样的初学者来说就是很实用。还记得都是搜什么&#xff0c;求最大值&#xff0c;最小值&#xf…

Redis热点数据处理

1、概念热点数据就是访问量特别大的数据。2、热点数据引起的问题流量集中&#xff0c;达到物理网卡上限。请求过多&#xff0c;缓存分片服务被打垮。redis作为一个单线程的结构&#xff0c;所有的请求到来后都会去排队&#xff0c;当请求量远大于自身处理能力时&#xff0c;后面…

RabbitMQ消息可靠性问题、死信交换机、延迟消息、惰性队列

目录消息可靠性生产者确保将消息成功送入队列消息确认消息回执消费者确保消息成功从队列中取出并成功消费消费确认机制消费失败重试机制失败策略使用第三种方式&#xff1a;消费者指定失败后转发的交换机使用第一种方式&#xff1a;在队列中指定死信交换机消息持久化问题交换机…

软件测试常见性能问题案例分析

在用户场景不确定的情况下&#xff0c;我们为了保障软件的正常运行就必须对软件的性能进行测试。下面我们一起来看看在软件测试中常见的性能问题&#xff0c;希望大家可以通过这七个比较典型的案例分析&#xff0c;充分掌握各种性能问题的解决方法。 案例一&#xff1a;某次压…