【LeetCode热题100】打卡第42天:滑动窗口最大值搜索二维矩阵II

文章目录

  • 【LeetCode热题100】打卡第42天:滑动窗口最大值&搜索二维矩阵II
    • ⛅前言
  • 滑动窗口最大值
    • 🔒题目
    • 🔑题解
  • 搜索二维矩阵II
    • 🔒题目
    • 🔑题解

【LeetCode热题100】打卡第42天:滑动窗口最大值&搜索二维矩阵II

⛅前言

大家好,我是知识汲取者,欢迎来到我的LeetCode热题100刷题专栏!

精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,熟练掌握这 100 道题,你就已经具备了在代码世界通行的基本能力。在此专栏中,我们将会涵盖各种类型的算法题目,包括但不限于数组、链表、树、字典树、图、排序、搜索、动态规划等等,并会提供详细的解题思路以及Java代码实现。如果你也想刷题,不断提升自己,就请加入我们吧!QQ群号:827302436。我们共同监督打卡,一起学习,一起进步。
博客主页💖:知识汲取者的博客
LeetCode热题100专栏🚀:LeetCode热题100

Gitee地址📁:知识汲取者 (aghp) - Gitee.com

题目来源📢:LeetCode 热题 100 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台

PS:作者水平有限,如有错误或描述不当的地方,恳请及时告诉作者,作者将不胜感激

滑动窗口最大值

🔒题目

原题链接:239.滑动窗口最大值

image-20230721101215009

🔑题解

  • 解法一:递减队列

    所谓的递减队列就是队头到队尾的元素按照从大到小的顺序进行排序的

    算法的核心步骤:

    1. 添加元素,要保障单调队列中的元素是递减的,由于添加元素是在队尾进行的,所以要求队列中其他元素都要比它大
    2. 移除元素,由于移除元素是在队头进行的,如果当前元素是最大值,需要移除单调队列的队头元素(队头元素就是当前最大值)

    对于这种题目我现在也不是一开始就没有思路了,一下就想到肯定要使用 递减队列 ,但是目前实现起来还是有一点困难,经过不断的debug调试,然后再不断优化代码的语句和逻辑判断,最终还是实现了,现在我就来说说我实现的思路吧:我们①首先需要构建两个队列,一个队列(可以是普通队列)用于存储滑动窗口中的元素,一个队列(只能是双端队列)用于记录当前窗口最大值,②这个双端队中的元素是递减的,这样能够保障队尾元素总是当前最大元素,我们要获取当前最大元素,只需要获取队尾元素即可③移除元素时,如果发现移除的元素是当前最大值,需要移除双端队列的队尾元素,这里不罗嗦了,直接画图吧

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m8f6nOFf-1690024629049)(https://gitee.com/aghp/typora-img/raw/master/csdn/202307221916698.gif)]

    本题可以参考:【LeetCode热题100】打卡第35天:最小栈

    import java.util.Deque;
    import java.util.LinkedList;/*** @author ghp* @title*/
    public class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int[] ans = new int[nums.length - k + 1];DescQueue queue = new DescQueue();// 初始化窗口for (int i = 0; i < k; i++) {queue.add(nums[i]);}int j = 0;ans[j++] = queue.getMax();// 向右滑动窗口for (int i = k; i < nums.length; i++) {queue.remove();queue.add(nums[i]);ans[j++] = queue.getMax();}return ans;}
    }class DescQueue {private Deque<Integer> queue;private Deque<Integer> maxQueue;public DescQueue() {this.queue = new LinkedList<>();this.maxQueue = new LinkedList<>();}/*** 新增元素到队列尾部** @param val*/public void add(int val) {queue.offer(val);while (!maxQueue.isEmpty() && maxQueue.peekLast() < val) {// 新增元素大于maxQueue队尾元素,不符合递减队列的要求// 需要移除队尾元素,直到maxQueue符合递减队列为止maxQueue.pollLast();}// 新增元素大于等于队尾元素,符合递增队列,直接添加到队尾maxQueue.offer(val);}/*** 移除队列头部元素*/public void remove() {int val = queue.poll();if (val == maxQueue.peek()) {// 移除的队头元素是当前最大值,则需要更新maxQueuemaxQueue.poll();}}/*** 获取当前队列中最大元素** @return*/public int getMax() {// maxQueue的头部元素即为当前最大值,直接返回即可return maxQueue.peek();}
    }
    

    复杂度分析:

    • 时间复杂度: O ( n ) O(n) O(n)
    • 空间复杂度: O ( n ) O(n) O(n)

    其中 n n n 为数组中元素的个数

    这里需要了解一下队列的几个常用API,不要搞混了,队列是队尾进队头出,队尾操作有:offerpollLastpeekLastgetLast;队头操作有:pollpeekelementgetFirst

    代码优化:空间优化

    前面我们使用了两个队列,一个队列存储窗口中的元素,一个队列记录当前最大值,我们可以发现对于本题,我们其实可以发现我们只需要知道当前窗口中的最大值即可,并不需要去记录当前窗口中所有的元素,所以这里我们可以对上面的代码进行一个改造,从而省略一个队列的开销,从而一定程度降低空间复杂度,那么我们该如何实现呢,这里给出主要思路:

    1. 添加元素,要保障单调队列中的元素是递减的,由于添加元素是在队尾进行的,所以要求队列中其他元素都要比它大
    2. 移除元素,我们不必像之前一样直接移除左边界元素,但是我们队列中存储的数组的索引,我们可以换一种思路,只有当最大值被移除时,才更新递减队列(DescQueue)

    总的思路还是和上一题大差不差的,空间复杂度没有降低,但是减少了内存占用

    备注:优化参考LeetCode官方题解

    import java.util.Deque;
    import java.util.LinkedList;/*** @author ghp* @title*/
    public class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int[] ans = new int[nums.length - k + 1];DescQueue queue = new DescQueue();// 初始化窗口for (int i = 0; i < k; i++) {queue.add(nums, i);}ans[0] = nums[queue.getMax()];// 向右滑动窗口for (int i = k; i < nums.length; i++) {queue.remove(i - k);queue.add(nums, i);ans[i - k + 1] = nums[queue.getMax()];}return ans;}
    }class DescQueue {private Deque<Integer> maxQueue;public DescQueue() {this.maxQueue = new LinkedList<>();}/*** 新增元素到队列尾部** @param arr* @param i*/public void add(int[] arr, int i) {while (!maxQueue.isEmpty() && arr[i] > arr[maxQueue.peekLast()]) {// 新增元素大于maxQueue队尾元素,不符合递减队列的要求// 需要移除队尾元素,直到maxQueue符合递减队列为止maxQueue.pollLast();}// 新增元素大于等于队尾元素,符合递增队列,直接添加到队尾maxQueue.offer(i);}/*** 移除队列头部元素*/public void remove(int i) {while (!maxQueue.isEmpty() && maxQueue.peek() <= i) {// 队头元素的索引已经超出了左边界,直接移除(队头元素已过期)maxQueue.poll();}}/*** 获取当前队列中最大元素** @return*/public int getMax() {// maxQueue的头部元素即为当前最大值,直接返回即可return maxQueue.peek();}
    }
    
  • 解法二:优先队列

    优先队列可能比前面的单调队列还要简单很多,思路也超级简单,这里就简单讲解一下:

    1. 构造优先队列(这一步是核心步骤),我们创建一个优先队列,队列中的元素是一个数组,数组的第一个元素是添加的nums数组的值,第二个元素是nums数组值对应的索引
    2. 添加元素,直接添加即可,优先队列底层会通过维护一个大根堆实现降序排序,即队头元素到队尾元素的值从大到小排序

    其实说白了优先队列本质也是一个单调队列思想,只是这个单调对了不需要我们自己维护,相较于解法一,本方法就简单太多了

    import java.util.PriorityQueue;/*** @author ghp* @title*/
    public class Solution {public int[] maxSlidingWindow(int[] nums, int k) {int[] ans = new int[nums.length - k + 1];// 创建一个优先队列,并且根据数组第一个元素进行降序排列,第一个元素是值,第二个元素是索引PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> b[0] - a[0]);// 初始化窗口for (int i = 0; i < k; i++) {pq.offer(new int[]{nums[i], i});}int j = 0;ans[j++] = pq.peek()[0];// 向右滑动窗口for (int i = k; i < nums.length; i++) {while (!pq.isEmpty() && pq.peek()[1] <= i - k) {// 队头元素的索引已经超出了左边界,直接移除(队头元素已过期)pq.poll();}pq.offer(new int[]{nums[i], i});ans[j++] = pq.peek()[0];}return ans;}
    }
    

    复杂度分析:

    • 时间复杂度: O ( n ) O(n) O(n)
    • 空间复杂度: O ( n l o g k ) O(nlogk) O(nlogk)

    其中 n n n 为数组中元素的个数, k k k是窗口的大小

搜索二维矩阵II

🔒题目

原题链接:240.搜索二维矩阵II

image-20230722181524442

🔑题解

  • 解法一:暴力枚举(能过)

    class Solution {public boolean searchMatrix(int[][] matrix, int target) {for (int[] row : matrix) {for (int element : row) {if (element == target) {return true;}}}return false;}
    }
    

    复杂度分析

    • 时间复杂度: O ( m n ) O(mn) O(mn)
    • 空间复杂度: O ( 1 ) O(1) O(1)

    其中m是行,n是列

  • 解法二:二分查找

    二分查找的简单应用,这里就不展开讲了,唯一需要注意的就是边界问题,对于边界问题的判断,实在不会判断的,有两种选择,一种是直接举例列出边界条件,一种是记口诀,像这种经典的算法,一般都有前辈总结的口诀,但是我还是比较推荐使用距离列出边界条件,记忆口诀这个东西太死了,失去了算法本身的意义,算法不是为了死记硬背,而是在于理解

    此外和这个题目相似的题还有很多,可以直接搜索关键词:二分查找

    /*** @author ghp* @title*/
    class Solution {public boolean searchMatrix(int[][] matrix, int target) {int row = matrix.length;for (int i = 0; i < row; i++) {Integer result = binarySearch(matrix[i], target);if (result != null) {return true;}}return false;}private Integer binarySearch(int[] arr, int target) {int l = 0, r = arr.length-1;while (l <= r) {int mid = (r - l) / 2 + l;if (target == arr[mid]) {return mid;} else if (target < arr[mid]) {r = mid - 1;} else {l = mid + 1;}}return null;}
    }
    

    复杂度分析:

    • 时间复杂度: O ( m l o g n ) O(mlogn) O(mlogn)
    • 空间复杂度: O ( 1 ) O(1) O(1)

    其中 n n n 为数组中元素的个数

  • 解法三:Z字形查找

    这个解法来自LeetCode官网,真TM强,没想到啊啊啊啊😫

    核心思路:充分利用层与层之间的排序关系,从右上角开始,不断比较当前坐标的值和目标值,缩小搜索范围,每一次比较都能缩小一行或一列的数据

    PS:能画一个动图就好了,我相信大家一看就懂(大家脑补一下吧,画图太费时间了),这个解法理解起来并不难,就是想不到啊

    class Solution {public boolean searchMatrix(int[][] matrix, int target) {int m = matrix.length, n = matrix[0].length;int row = 0, col = n - 1;while (row < m && col >= 0) {if (matrix[row][col] == target) {return true;}if (matrix[row][col] > target) {// 目标值比当前坐标值要小,则向左逼近--col;} else {// 目标值比当前坐标值要大,则向下逼近++row;}}return false;}
    }
    

    复杂度分析

    • 时间复杂度: O ( m + n ) O(m+n) O(m+n),每次都会缩小一行或一列的数据,所以最坏情况,时间复杂度是 O ( m + n ) O(m+n) O(m+n),也就是目标值在左下角
    • 空间复杂度: O ( 1 ) O(1) O(1)

    其中m是行,n是列

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

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

相关文章

SpringMVC程序开发

1.什么是Spring MVC? Spring Web MVC是基于Servlet API构建的原始的Web框架&#xff0c;从一开始是就包含在Spring框架中。它的正式名称“Spring Web MVC"来自其源模板的名称&#xff08;Spring-webmvc)&#xff0c;但通常被称为“Spring MVC" 从上述的定义我们可…

[visionOS][Apple Vision Pro] 缩放3D模型

方法一&#xff1a;通过代码来设置Model3D Model3D(named:"你的3D模型名称",bundle:realityKitContentBundle).padding(.bottom,50).scaleEffect(0.2) //这句用来缩放 方式二&#xff1a;别人可以&#xff0c;我验证过不行的方法 RealityKitContent工具中&#xf…

PLC-Recorder的高速采集有多快?0.5ms算快吗?看控制器能力了!

大家知道&#xff0c;PLC-Recorder有一个高速采集的功能&#xff0c;基于TCP连接或UDP报文&#xff0c;速度取决于发送端的能力。对于西门子PLC&#xff0c;能做到1-2ms的采集速度&#xff0c;但是&#xff0c;我在前面的文章里提到了0.5ms的高速采集&#xff0c;哪个控制器能这…

Linux 下 nc 发送接收 udp、tcp数据

nc&#xff0c;全名叫 netcat&#xff0c;它可以用来完成很多的网络功能&#xff0c;譬如端口扫描、建立TCP/UDP连接&#xff0c;数据传输、网络调试等等&#xff0c;因此&#xff0c;它也常被称为网络工具的 瑞士军刀 。 一、只服务端使用nc 备注&#xff1a;这种方式只能发…

Django实现音乐网站 ⑴

使用Python Django框架制作一个音乐网站。 目录 网站功能模块 安装django 创建项目 创建应用 注册应用 配置数据库 设置数据库配置 设置pymysql库引用 创建数据库 创建数据表 生成表迁移文件 执行表迁移 后台管理 创建管理员账户 启动服务器 登录网站 配置时区…

自媒体必备的8个素材网站,视频、音效、图片全部免费下载

自媒体必备的视频、音效、图片素材&#xff0c;这8个网站帮你解决。赶紧马住&#xff01; 菜鸟图库 https://www.sucai999.com/video.html?vNTYwNDUx 菜鸟图库虽然是一个设计网站&#xff0c;但它还有非常丰富的视频和音频素材&#xff0c;视频素材全部都是高清无水印&#…

Java 贪心算法经典问题解决

文章目录 分金条题目思路代码实现测试用例以及结果输出 花费资金做项目最大收益题目思路代码实现测试用例以及结果输出 预定会议室题目思路代码实现测试用例以及结果输出 取中位数题目思路代码实现测试用例以及结果输出 最低字典序题目思路代码实现测试用例以及结果输出 结语 分…

vite打包性能优化以及填坑

目录 前言 项目优化前 分析 优化 拆分包 去除debugger CDN 加速 按需导入 文件压缩 图片压缩 viteImagemin报错 填坑 坑1 坑2 总结 配置 前言 最近在使用 Vite4.0 构建一个中型前端项目的过程中&#xff0c;遇到了一些坑&#xff0c;也做了一些项目在构建生产环…

C进阶:文件操作

C语言文件操作 什么是文件 磁盘上的数据是文件。 但是在程序设计中&#xff0c;我们一般谈的文件有两种&#xff1a;程序文件&#xff08;例如.c,.h这一类编译&#xff0c;链接过程中的文件&#xff09;&#xff0c;数据文件。 程序文件 包括源程序文件&#xff08;后缀为.c&…

重生之我要学C++第四天

这篇文章的主要内容是类的默认成员函数。如果对大家有用的话&#xff0c;希望大家三连支持&#xff0c;博主会继续努力&#xff01; 目录 一.类的默认成员函数 二.构造函数 三.析构函数 四.拷贝构造函数 五.运算符重载 一.类的默认成员函数 如果一个类中什么成员都没有&…

JavaWeb 速通HTTP

目录 一、HTTP快速入门 1.HTTP简介 : 2.HTTP请求头 : 3.HTTP响应头 : 二、HTTP响应状态码 1.基本介绍 : 2.常见状态码 : 3.状态码的分类 : 4.完整状态码汇总 : 三、HTTP请求包和响应包 1.请求包分析 : 1 GET请求 (1) 说明 (2) doGet返回数据给浏览器 (3) form表单提…

Hadoop生态体系-2

目录标题 1、MapReduce介绍2、数据仓库3、HIVE4、HQL4.1 hive读写文件机制4.2 Hive数据存储路径 1、MapReduce介绍 思想&#xff1a;分而治之 map:“分”&#xff0c;即把复杂的任务分解为若干个“简单的任务”来处理。可以进行拆分的前提是这些小任务可以并行计算&#xff0c…

C++ 函数重载

1.函数重载的概念 在C中可以为两个或两个以上的函数提供相同的函数名称&#xff0c;只要参数类型不同&#xff0c;或参数类型相同而参数个数不同&#xff0c;称为函数重载。 在C语言中实现int&#xff0c;char&#xff0c;double类型的比较大小函数&#xff1a; int my_max_…

【Kubernetes资源篇】ingress-nginx最佳实践详解

文章目录 一、Ingress Controller理论知识1、Ingress Controller、Ingress简介2、四层代理与七层代理的区别3、Ingress Controller中封装Nginx&#xff0c;为什么不直接用Nginx呢&#xff1f;4、Ingress Controller代理K8S内部Pod流程 二、实践&#xff1a;部署Ingress Control…

STM32 串口实验(学习一)

本章将实现如下功能&#xff1a;STM32通过串口和上位机对话&#xff0c;STM32在收到上位机发过来的字符串后&#xff0c;原原本本返回给上位机。 STM32 串口简介 串口作为MCU的重要外部接口&#xff0c;同时也是软件开发重要的调试手段&#xff0c;其重要性不言而喻。现在基本…

KMP算法的及其原理

KMP算法 首先 我们先了解一下 KMP算法的作用 str1 和str2 字符串 如果str1中包含str2 那么返回头位置 如果不包含返回-1 首先 我们先加入一个概念: 有一个next数组 next[i]的值为 str2 中 以i-1位置为结尾的字符串中 最长相同前缀后缀为多长(相同前缀后缀 不是对称 aba 中相…

uniapp 小程序如何从主包页面跳转到分包页面

在uniapp开发小程序的时候&#xff0c;“分包”概念一定要提前了解下&#xff0c;具体我就不多说了&#xff0c;自己看下关网的相关配置。 那么&#xff0c;如果从主包页面&#xff0c;跳转至分包的页面呢&#xff1f;如图所示 我的页面->详情页 在我的页面创建好自己的链…

ARM--LED灯点亮

LED1,LED2,LED3亮灯 .text .global _start_start: /**********LED1点灯--->PE10**************//*初始化RCC章节*/通过RCC_MP_AHB4ENSETR寄存器,使能GPIOs组控制器 0x500000A28[4] 1RCC_INIT: E组和F组一起使能ldr r0,0x50000A28 ldr r1,[r0]orr r1,r1,#(0x3 << 4)s…

vue3+ts+elementui-plus二次封装树形表格实现不同层级展开收起的功能

一、TableTreeLevel组件 <template><div classmain><div class"btns"><el-button type"primary" click"expandLevel(1)">展开一级</el-button><el-button type"primary" click"expandLevel(2…

13年测试老鸟,接口性能测试总结整理,据说这是全网最全的...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 性能测试按照不同…