力扣 二叉树 相关题目总结2

news2024/12/24 3:36:50

 

目录

一、101 对称二叉树

题目

题解

方法一:递归(推荐)

方法二:迭代

二、100 相同的树

题目

题解

方法一:递归法

方法二:深度优先搜索

三、111 二叉树的最小深度

题目

题解

方法一:递归法

四、226 翻转二叉树

题目

题解


一、101 对称二叉树

题目

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

示例 1:
输入:root = [1,2,2,3,4,4,3]
输出:true

示例 2:
输入:root = [1,2,2,null,3,null,3]
输出:false
 
提示:
树中节点数目在范围 [1, 1000] 内
-100 <= Node.val <= 100

题解

方法一:递归(推荐)

乍一看无从下手,但用递归其实很好解决。

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

根据题目的描述,镜像对称,就是左右两边相等,也就是左子树和右子树是相当的。注意这句话,左子树和右子相等,也就是说要递归的比较左子树和右子树。

我们将根节点的左子树记做 left,右子树记做 right。比较 left 是否等于 right,不等的话直接返回就可以了。如果相当,比较 left 的左节点和 right 的右节点,再比较 left 的右节点和 right 的左节点。

比如看下面这两个子树(他们分别是根节点的左子树和右子树),能观察到这么一个规律:

  • 左子树的左孩子 == 右子树的右孩子
  • 左子树的右孩子 == 右子树的左孩子

(1)确定终止条件

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

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

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

此时已经排除掉了节点为空的情况,那么剩下的就是左右节点不为空:左右都不为空,比较节点数值,不相同就return false。

此时左右节点不为空,且数值也不相同的情况我们也处理了。根据上面信息可以总结出递归函数的两个终止条件:

  1. left 和 right 不等,或者 left 和 right 都为空
  2. 递归的比较 left.left 和 right.right,递归比较left.right 和 right.left

(2)确定单层递归的逻辑

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

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

(3)代码如下,

class Solution {
    public boolean isSymmetric(TreeNode root) {
        if (root == null) {
            return true;  // 如果根节点为null,即空树,视为对称二叉树,返回true
        }
        return isMirror(root.left, root.right);  // 调用isMirror方法判断左子树和右子树是否对称
    }

    private boolean isMirror(TreeNode left, TreeNode right) {
        if (left == null && right == null) {
            return true;  // 如果左子树和右子树都为null,也视为对称,返回true
        }
        if (left == null || right == null) {
            return false;  // 如果左子树和右子树只有一个为null,视为不对称,返回false
        }
        return left.val == right.val && isMirror(left.left, right.right) && isMirror(left.right, right.left);
        // 如果左子树和右子树的值相等,且同时满足左子树的左子树和右子树的右子树对称,
        // 以及左子树的右子树和右子树的左子树对称,则视为对称,返回true;否则,返回false
    }
}

isSymmetric方法是该函数的入口,接收一个二叉树的根节点作为参数。

  • 首先判断根节点是否为null,如果是,即空树,视为对称二叉树,返回true。否则,调用isMirror 方法来判断左子树和右子树是否对称。

isMirror方法是递归判断左右子树是否对称的函数。

  • 首先判断左子树和右子树是否都为null,如果是,即均为空树,视为对称,返回true。
  • 然后判断左子树和右子树中只有一个为null的情况,即一个为空树一个不为空树,视为不对称,返回false。
  • 最后,判断左子树的值和右子树的值是否相等,并且同时递归判断左子树的左子树和右子树的右子树是否对称,以及递归判断左子树的右子树和右子树的左子树是否对称。只有全部满足才视为对称,返回true;否则,返回false。

时间复杂度是O(n),因为我们遍历整个输入树一次,所以总的运行时间为 O(n),其中 n 是树中结点的总数。

空间复杂度:递归调用的次数受树的高度限制。在最糟糕情况下,树是线性的,其高度为 O(n)。因此,在最糟糕的情况下,由栈上的递归调用造成的空间复杂度为 O(n)。

方法二:迭代

这道题目我们也可以使用迭代法,使用队列来比较两个树(根节点的左右子树)是否相互翻转,(注意这不是层序遍历)。

回想下递归的实现:当两个子树的根节点相等时,就比较:左子树的 left 和 右子树的 right,这个比较是用递归实现的。

现在我们改用队列来实现,把左右两个子树要比较的元素顺序放进一个容器,然后成对成对的取出来进行比较,那么其实使用栈也是可以的。思路如下:

  • 首先从队列中拿出两个节点(left 和 right)比较:
  • 将 left 的 left 节点和 right 的 right 节点放入队列
  • 将 left 的 right 节点和 right 的 left 节点放入队列

代码如下,

public static boolean isSymmetric(TreeNode root){
    Deque<TreeNode> deque = new LinkedList<>();
    deque.offerFirst(root.left);
    deque.offerLast(root.right);
    while (!deque.isEmpty()) {
        TreeNode leftNode = deque.pollFirst();
        TreeNode rightNode = deque.pollLast();
        if (leftNode == null && rightNode == null) {
            continue;
        }
        if (leftNode == null || rightNode == null || leftNode.val != rightNode.val) {
            return false;
        }
        deque.offerFirst(leftNode.left);
        deque.offerFirst(leftNode.right);
        deque.offerLast(rightNode.right);
        deque.offerLast(rightNode.left);
    }
    return true;
}

使用双端队列 Deque 来存储需要比较的节点。将根节点的左子节点和右子节点添加到队列中。

当队列不为空时,进入循环。从队列中取出两个节点 left 和 right 进行比较。注意,这里使用 poll 方法每次从队列中取出两个节点。

如果两个节点都为空,则继续下一次循环,因为两个空节点是对称的。如果一个节点为空或者两个节点的值不同,则树不对称,返回 false

如果两个节点相等且不为空,将 left 节点的左子节点和 right 节点的右子节点加入队列的前端。将 left 节点的右子节点和 right 节点的左子节点加入队列的末端。这种方式确保了每次都比较成对的子节点,以保持对称性。

二、100 相同的树

题目

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

提示:
两棵树上的节点数目都在范围 [0, 100] 内
-104 <= Node.val <= 104

题解

题意讲的很清楚,就是判断两颗二叉树是否完全相同,其实就可以梳理成以下三点:

  • p 树的根节点和 q 树的根节点比较。
  • p 树的左子树和 q 树的左子树比较。
  • p 树的右子树和 q 树的右子树比较。

方法一:递归法

具体算法代码实现如下:

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        // 皆空,直接返回
        if(p == null && q == null)  return true;
        // 如果其中一棵树为空,另一棵不为空,则一定不相同
        if((p == null && q != null) || (p != null && q == null)) return false;
        // 如果两棵树皆不为空,但是根节点的值不同,则一定不相同。
        if(p.val !=q.val) return false;

        //排除以上特殊情况,只需要都为true则说明两树完全相同。
        return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);    
    }
}

时间复杂度:O(min(n,m))。其中 m 和 n 分别是两个二叉树的节点数。对两个二叉树同时进行深度优先搜索,只有当两个二叉树中的对应节点都不为空时才会访问到该节点,因此被访问到的节点数不会超过较小的二叉树的节点数。

空间复杂度:O(min(m,n))。其中 m 和 n 分别是两个二叉树的节点数。空间复杂度取决于递归调用的层数,递归调用的层数不会超过较小的二叉树的最大高度,最坏情况下,二叉树的高度等于节点数。

方法二:深度优先搜索

具体算法代码实现如下:

class Solution {
    public boolean isSameTree(TreeNode p, TreeNode q) {
        //两数都为空,直接返回
        if (p == null && q == null) {
            return true;
        //存在一方为空,则不可能相同
        } else if (p == null || q == null) {
            return false;
        } else if (p.val != q.val) {
            return false;
        } else {
            return isSameTree(p.left, q.left) && isSameTree(p.right, q.right);
        }
    }
}

时间复杂度:O(min(m,n))。其中 m 和 n 分别是两个二叉树的节点数。对两个二叉树同时进行深度优先搜索,只有当两个二叉树中的对应节点都不为空时才会访问到该节点,因此被访问到的节点数不会超过较小的二叉树的节点数。

空间复杂度:O(min(m,n))。其中 m 和 n 分别是两个二叉树的节点数。空间复杂度取决于递归调用的层数,递归调用的层数不会超过较小的二叉树的最大高度,最坏情况下,二叉树的高度等于节点数。

其实以上两种思路本质上都差不多的,唯独就是解题思路方向上细致不太一样。都是是运用递归思想,连枚举方式都是一样的,先枚举排除特殊性,然后再递归对比左右子数是否相等。

三、111 二叉树的最小深度

题目

给定一个二叉树,找出其最小深度。

最小深度是从根节点到最近叶子节点的最短路径上的节点数量。

说明:叶子节点是指没有子节点的节点

示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:2

示例 2:
输入:root = [2,null,3,null,4,null,5,null,6]
输出:5

题解

方法一:递归法

递归计算每个结点的最小深度

  • 当当前节点是空,直接返回
  • 当左子树是空,且右子树不为空,则返回 右子树的最小深度 + 1
  • 当右子树是空,且左子树不为空,则返回 左子树的最小深度 + 1
  • 当左右子树均不为空,则返回 左右子树的最小深度的最小值 + 1

时间复杂度 O(n),n 为二叉树的节点数,需要遍历二叉树的所有节点。

class Solution {
    public int minDepth(TreeNode root) {
        if(root == null) return 0;
        int l = minDepth(root.left);
        int r = minDepth(root.right);
        if(root.left == null && root.right != null) return 1 + r;
        if(root.right == null && root.left != null) return 1 + l;
        return 1 + Math.min(l, r);
    }
}

 

四、226 翻转二叉树

题目

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

提示:
树中节点数目范围在 [0, 100] 内
-100 <= Node.val <= 100

题解

翻转一棵二叉树意味着交换每个节点的左右子树。我们可以使用递归的方法,从根节点开始,对每个节点进行如下操作:

  • 交换当前节点的左右子树
  • 递归地翻转当前节点的左子树
  • 递归地翻转当前节点的右子树

递归的终止条件是当前节点为 null,即叶子节点。

代码如下,

class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null) return root;

        TreeNode temp = root.left;
        root.left = root.right;
        root.right= temp;

        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
}

递归函数需要访问每个节点恰好一次,因此时间复杂度为 O(n),其中 n 是树中节点的数量。

递归函数在递归过程中使用的栈空间的最大深度等于树的高度,最坏情况下,树是一个链表结构,高度为 n,因此空间复杂度为 O(n)。

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

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

相关文章

单点触摸屏和多点触摸屏介绍以及原理简略

单点和多点触摸屏技术是现代触摸设备的基础&#xff0c;下述简单解释这两种技术及其差异。 单点触摸屏 单点触摸屏只能在某一时刻检测一个触摸点的位置。这种触摸屏适用于简单的触摸交互&#xff0c;如点击和拖动。 工作原理 单点触摸屏主要通过以下几种技术实现&#xff1…

VS编译和使用modbus库

一.libmodbus 库 免费的开源的&#xff0c;modbus 开发库&#xff0c;支持 RTU 和 TCP 官网&#xff1a;libmodbus.org 在线文档&#xff1a;https://libmodbus.org/reference/ 二.源码简介 项目说明doc 目录各 API 接口的详细说明文档src 目录源码都在这个目录下tests 目录…

【Redis从0到1进阶】Redis 持久化

笔记内容来自B站博主《遇见狂神说》&#xff1a;Redis视频链接 Redis 是内存数据库&#xff0c;如果不将内存中的数据库状态保存到磁盘&#xff0c;那么一旦服务器进程退出&#xff0c;服务器中的数据库状态也会消失。所有Redis 提供了持久化功能&#xff01; 一、RDB&#xff…

pixelRNN与pixelCNN

目的&#xff1a;为了找到一个最能解释得到的生成样本的模型 PixelRNN 我们需要利用概率链式法则将图像x的生成概率转变为每个像素生成概率的乘积&#xff0c;也就是每个通道生成概率的乘积。 公式&#xff1a; 公式解释&#xff1a;p(x)是每个图像x的概率&#xff1b;右侧为…

一文快速接入银行卡识别API

银行卡识别API 能通过机器学习和图像识别技术来解析银行卡相关信息&#xff0c;根据用户上传卡片自动识别内容&#xff0c;返回该卡的卡号、所属银行及银行类型等信息。可以在用户需要输入银行卡等相关信息时使用该功能&#xff0c;帮助用户快速输入正确信息&#xff0c;简化用…

PE文件(十一)移动导出表和重定位表

移动表的原因 一个PE文件中有很多节&#xff0c;每个节都存储不同的数据。而PE文件中的各种表也都分散存储在这些节当中。此时各种表的信息与程序的代码和数据相互混合在一起&#xff0c;如果我们直接对整个程序进行加密&#xff0c;那系统在初始化程序时就会出问题。比如&…

2024年7月9日~2024年7月15日周报

目录 一、前言 二、完成情况 2.1 特征图保存方法 2.1.1 定义网络模型 2.1.2 定义保存特征图的钩子函数 2.1.3 为模型层注册钩子 2.1.4 运行模型并检查特征图 2.2 实验情况 三、下周计划 一、前言 本周的7月11日~7月14日参加了机器培训的学习讨论会&#xff0c;对很多概…

iredmail服务器安装步骤详解!如何做配置?

iredmail服务器安全性设置指南&#xff1f;怎么升级邮件服务器&#xff1f; iredmail是一个功能强大的邮件服务器解决方案&#xff0c;它集成了多个开源软件&#xff0c;使您能够快速部署和管理邮件服务。AokSend将逐步引导您完成安装过程&#xff0c;无需深入的编程知识即可轻…

springboot的Filter过滤器拦截资源

配置拦截器&#xff0c;要加上ServletComponentScan和WebFilter(urlPatterns "/*")注解一起使用

基于Java的斗地主游戏案例开发(做牌、洗牌、发牌、看牌

package Game;import java.util.ArrayList; import java.util.Collections;public class PokerGame01 {//牌盒//♥3 ♣3static ArrayList<String> list new ArrayList<>();//静态代码块//特点&#xff1a;随着类的加载而在加载的&#xff0c;而且只执行一次。stat…

如何评估代理的可靠性和安全性

使用IP代理最主要的是要看是否安全&#xff0c;代理IP是否稳定可靠&#xff0c;但是又如何评估一个代理IP的安全性与可靠性呢&#xff0c;下面具体介绍一下。 评估代理的可靠性 服务稳定性 代理服务的稳定性直接影响到业务的连续性和效率。评估代理的服务稳定性重点查看下面…

vue2学习笔记1-官网使用指南和搭建开发环境

官网使用指南 官网地址&#xff1a;介绍 — Vue.js 1、学习 1.1 教程和API 最重要的两个板块。API是VUE的字典&#xff0c;需要时来查阅。 1.2、风格指南 如何写出风格优雅的VUE代码。规则分为四类&#xff1a;必要的&#xff0c;强烈推荐、推荐、谨慎使用。 1.3、示例 …

正点原子STM32(基于HAL库)6

目录 TFTLCD&#xff08;MCU 屏&#xff09;实验TFTLCD 简介TFTLCD 简介液晶显示控制器FSMC 简介FSMC 关联寄存器简介 硬件设计程序设计FSMC 和SRAM 的HAL 库驱动程序流程图程序解析 下载验证 LTDC LCD&#xff08;RGB 屏&#xff09;实验RGBLCD<DC 简介RGBLCD 简介LTDC 简介…

使用Keepalived实现双机热备(虚拟漂移IP地址)详细介绍

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f427;Linux基础知识(初学)&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; &#x1f510;Linux中firewalld防火墙&#xff1a;点击&#xff01; ⏰️创作…

影响代理运行速度的因素有哪些?

在当今数字化时代&#xff0c;代理服务器被广泛应用于网络接入、数据收集、隐私保护等各种场景。然而代理服务器的运行速度对用户体验和运行效率至关重要。在本文中&#xff0c;我们将讨论影响代理运行速度的主要因素&#xff0c;并介绍如何优化代理服务器以提高运行速度。 第一…

解决ESLint和Prettier冲突的问题

在配置了ESLint的项目中使用Prettier进行格式化可能会出现冲突&#xff0c;不如Prettier配置了使用双引号&#xff0c;ESLint配置了单引号&#xff0c;当然可以一个一个改成一样的配置&#xff0c;但是比较麻烦。我发现可以直接使用ESLint的规则进行格式化。在VSCode配置过程如…

【Orange Pi AIpro测评】基于OrangePi AIpro开发板从零搭建部署小雅影音库

文章目录 一、OrangePi AIpro介绍1.1 OrangePi AIpro 实物图1.2 OrangePi AIpro 示意图1.3 OrangePi AIpro详细信息介绍 二、为 OrangePi 安装 xfce4 桌面及 VNC 服务三、将 Ubuntu 镜像烧写到 TF 卡四、将 Ubuntu 镜像烧写到 NVMe SSD五、远程连接OrangePi AIpro的方式5.1 通过…

[C/C++入门][变量和运算]7、交换变量(空杯思想)

计算机中交换变量的值&#xff0c;可谓是非常常见&#xff0c;常见到几乎考试卷子里都有它。 如图&#xff0c;一杯牛奶&#xff0c;一杯咖啡&#xff0c;如何进行交换呢&#xff1f; 相信懂的都懂&#xff0c;不懂的看完这个图也就懂了。 生活中非常简单的例子&#xff0c;放…

新160个crackme - 003-Cruehead-CrackMe-3

运行分析 发现只有一个退出 PE分析 32位&#xff0c;未知程序&#xff0c;壳未知 静态分析 发现关键字符串 找到关键函数&#xff0c;分析函数&#xff0c;设置断点 动态调试 到断点到if语句&#xff0c;tab键切换至汇编代码 找到跳转语句 右键Assemble jnz改为jz然后回…

Matlab 判断直线上一点

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 判断一个点是否位于一直线上有很多方法,这里使用一种很有趣的坐标:Plucker线坐标,它的定义如下所示: 这个坐标有个很有趣的性质,我们可以使用Plucker坐标矢量构建一个Plucker矩阵: 则它与位于对应线上的齐次点…