【代码随想录训练营】【Day12休息】【Day13】第五章|栈与队列|239. 滑动窗口最大值|347.前 K 个高频元素|总结

news2024/9/20 9:01:54

239.滑动窗口最大值

题目详细:LeetCode.239

看到滑动窗口,我立马想起了双指针,利用双指针可以非常清晰地理解解题思路:

  • 定义一个变量 max_i 用于记录窗口中的最大值的索引
  • 每次窗口滑动后
    • 如果出去的值是最大值,那么新的窗口则需要重新查找最大值并设置 max_i
      • 这里使用双指针查找窗口中的最大值
    • 如果出去的值不是最大值,则判断新进来的值是否大于当前的最大值
      • 不大于则最大值可不变
      • 大于则将进来的值作为最大值

这里我让 max_i 维护的是一个最大值的索引,当然维护一个最大值也是可以的,思路都是一样的

Java解法(双指针,维护最大值索引):

class Solution {
    public int getMaxIndex(int[] nums, int l, int r){
        while(l < r){
            if(nums[l] < nums[r]){
                l++;
            }else{
                r--;
            }
        }
        return l;
    }

    public int[] maxSlidingWindow(int[] nums, int k) {
        int max_i = -1;
        List<Integer> ans = new ArrayList<>();
        for(int i = 0; i <= nums.length - k; i++){
            int l = i, r = i + k - 1;
            if(max_i == -1 || max_i < l){
                //如果出去的值是最大值(的索引),那么新的窗口需要重新查找最大值并设置
                max_i = getMaxIndex(nums, l, r);
            }else{
                //如果出去的值不是最大值(的索引),则判断新进来的值是否大于当前的最大值
                //不大于则最大值(的索引)不变
                //大于则将进来的值(的索引)作为最大值(的索引)
                if(nums[r] >= nums[max_i]){
                    max_i = r;
                }
            }
            ans.add(nums[max_i]);
        }
        return ans.stream().mapToInt(Integer::valueOf).toArray();
    }
}
  • 解题思路非常好理解,通过观察滑动窗口的特点也可以发现,其具备了队列先进先出的特点,所以也可以视作是利用双指针模拟了一个单向队列
  • 但这道题用Java来解,这样写的话在经过LeetCode测试用例时,会出现超出时间限制的问题
  • 所以我尝试使用队列来解题,思路是一样的,只是利用队列来维护最大值的索引,发现就不会出现超出时间限制的问题了

Java解法(队列,维护最大值索引):

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        List<Integer> ans = new ArrayList<>();
        Deque<Integer> dq = new LinkedList<>();
        for(int i=0; i < nums.length; i++){
            if(!dq.isEmpty() && i - dq.peek() == k){
                dq.poll();
            }
            while(!dq.isEmpty() && nums[i] > nums[dq.peekLast()]){
                dq.pollLast();
            }
            dq.add(i);
            if(i >= k - 1){
                ans.add(nums[dq.peek()]);
            }
        }
        return ans.stream().mapToInt(Integer::valueOf).toArray();
    }
}

347.前 K 个高频元素

题目详细:LeetCode.347

基本思路:

  • 为了统计每一个元素出现的频率,可以定义一个HashMap<数值, 频率>来进行统计
  • 统计完后,我们只需要对每个元素的频率从大到小进行排序,然后取出前K个频率对应元素即可

难点:

  • 本题的难点在于怎么对元素的出现频率进行排序,能够降低时间复杂度
  • 若使用快排对频率进行排序,其算法的时间复杂度是O(n*logn)

由题目可知:结果只需要前K个高频的元素

  • 那么我们可以始终维护一个大小为K的小顶堆
  • 对每次进堆的元素都做一次排序,使出现频率小的作为堆顶弹出
  • 最后堆中只会留下K个频率高的元素
  • 这样的算法的时间复杂度是O(n*logK)

在Java中, 是使用优先队列(PriorityQueue)来实现堆结构的,小顶堆即是指维护元素从小到大排序的队列。

Java解法(小顶堆排序(优先队列)):

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer, Integer> map = new HashMap<>();
        for(int n : nums){
            map.put(n, map.containsKey(n) ? map.get(n) + 1 : 1);
        }
        PriorityQueue<Map.Entry<Integer, Integer>> heap = new PriorityQueue<>((a,b) -> a.getValue()-b.getValue());
        for(Map.Entry<Integer, Integer> entry: map.entrySet()){
            heap.offer(entry);
            if(heap.size() > k){
                heap.poll();
            }
        }
        return heap.stream().mapToInt(e -> e.getKey()).toArray();
    }
}

这道题让我第一次接触到了优先队列,发现优先队列的实现其实就是堆的实现

  • Java给我们提供的优先队列容器(PriorityQueue)也就是堆容器,有大顶堆和小顶堆两种实现
    • PriorityQueue 默认实现的是小顶堆
    • new PriorityQueue<>((a,b) -> b - a) ,利用匿名重写其底层的比较方法,可以使其实现为大顶堆

总结

栈和队列是两个常用的数据结构:

  • 栈的特点是后进先出,队列的特点是先进先出

在Java中,队列的形式是多种多样的:

  • 栈(Stack)其底层是用双向队列(Deque)实现的
    • 因为双向队列在两端都实现了进队和出队操作
    • 既有后进先出也有先进先出的特点,所以只要堵住一端,就变成了栈
  • 常见的队列实现类有LinkedList、ArrayQeque和PriorityQueue
    • LinkedList:实现了Queue接口,所以可以将LinkedList直接当作队列来使用,Queue接口只是窄化了LinkedList方法的访问权限
    • ArrayQeque:实现了Queue接口,底层是利用数组存储,模拟队列的存储方式,是队列的线性实现
    • PriorityQueue:继承自AbstractQueue抽象类,在队列的实现基础上增加了维持队内元素次序的方法,常用于维护一个堆结构(大顶堆/小顶堆)
  • 还有阻塞队列(BlockingQueue)等等

Java中队列的依赖关系


经过对栈和队列的学习,让我对栈和队列各自的特点都有了非常深的印象,同时发现这两种数据结构虽然存储方式差异挺大,但两者其实相辅相成,灵活运用起来的时候可以非常迅速,非常清晰地解决一些问题。

而且在以前遇到滑动窗口相关的问题时,只会往双指针法或者暴力法方面思考,在学习过后,发现滑动窗口的滑动过程,其实也类似于队列左端出队,右端进队的过程,在以后解决相关问题时,又多了一种可以尝试的数据结构。

还有以前经常听人说优先队列,但是一直不知道优先队列是什么,但是通过刷题才发现,原来优先队列就是堆结构,还是算收获蛮大的。

栈和队列的理论基础很简单,但是它们在实际应用中,却是千变万化、难上加难,即各有千秋又相辅相成,可以延伸出许许多多各具特点的数据结构和各种殊途同归的解决思路来,真叫人:

纸上得来终觉浅,绝知此事要躬行。

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

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

相关文章

ChatGPT实火,这小东西牛在哪?

ChatGPT&#xff0c;真的火了啊&#xff01; 相信许多朋友都听说过 ChatGPT铺天盖地的赞美&#xff0c;但并不清楚它是个啥。 体制内让ChatGPT写材料&#xff0c;广告行业让ChatGPT写策划案&#xff0c;媒体让ChatGPT写新闻稿&#xff0c;程序员让ChatGPT写代码甚至还带修BUG服…

三、常用样式讲解一

文章目录一、企业站点样式实战1.1 版心1.2 reset.css1.3 index.css&#xff08;首页的样式&#xff09;1.4 溢出1.5 元素类型1.6 元素类型的转换1.7 行内块元素的特殊情况&#xff1a;img标签的特殊性一、企业站点样式实战 1.1 版心 1.2 reset.css /* reset.css用作清除一些常…

行人检测(人体检测)2:YOLOv5实现人体检测(含人体检测数据集和训练代码)

行人检测(人体检测)2&#xff1a;YOLOv5实现人体检测(含人体检测数据集和训练代码) 目录 行人检测(人体检测)2&#xff1a;YOLOv5实现人体检测(含人体检测数据集和训练代码) 1. 前言 2. 人体检测数据集说明 &#xff08;1&#xff09;人体检测数据集 &#xff08;2&#…

什么是互联网舆情监测分析系统,TOOM舆情监测云服务有哪些内容?

舆情监测应用范围广泛&#xff0c;可以帮助企业了解品牌形象、产品口碑、市场竞争、消费者需求等信息&#xff0c;政府了解民意状况、政策反响、社会热点等信息&#xff0c;个人了解社会趋势、舆论氛围、公共事件等信息。同时&#xff0c;舆情监测分析也可以帮助相关决策者及时…

男生vs女生,谁更加适合做软件测试?

前言 随着互联网的飞速发展&#xff0c;软件测试行业同步兴盛起来&#xff0c;逐渐出现了人才的短缺&#xff0c;致使行业人员工资一涨再涨。 所以&#xff0c;越来越多的人也开始意识到软件测试行业的”高薪“属性&#xff0c;转身投入到相关的工作中来。 但是&#xff0c;…

【Spring Cloud】如何把Feign默认的HTTP客户端URLConnection更换成支持连接池的Apache HttpClient或OKHttp

本期目录前言1. Feign底层的客户端实现2. Feign性能优化思路3. 更换底层客户端1&#xff09;引入依赖坐标2&#xff09;配置连接池前言 本次示例代码的文件结构如下图所示。 1. Feign底层的客户端实现 Feign 发送 HTTP 请求时&#xff0c;底层会使用到别的客户端。下面列出…

微服务网关(四)tcp代理模块

微服务网关&#xff08;四&#xff09;tcp代理模块 tcp代理服务器的代理实现&#xff1a; 请求流程&#xff1a; 代理的启停方法 //并发执行 go func() {tcp_proxy_router.TcpServerRun() }()tcp_proxy_router.TcpServerStop()tcp_server 一次完整流程 tcp_server.go 首先…

JVM的垃圾回收机制

复制算法、Eden区和Survivor区 首先我们就来探索一下对于JVM堆内存中的新生代区域&#xff0c;是怎么进行垃圾回收的。 实际上JVM是把新生代分为三块区域的&#xff1a;1个Eden区&#xff0c;2个Survivor区。 其中Eden区占用80%的内存空间&#xff0c;每块Survivor各占用10%的内…

使用yolov5训练数据集笔记

准备工作 1. 安装labelimg labelimg:主要用于目标检测的目标框绘制&#xff0c;得到关于我们训练的边框位置、类别等数据 pip install labelimg2. 下载yolov5源码 我使用的是v7.0版本&#xff0c;直接下载即可&#xff0c;下载后解压出来 2.1 安装yolov5运行依赖包 进入…

SurfaceFlinger详解

SurfaceFlinger的定义 大多数应用在屏幕上一次显示三个层&#xff1a;屏幕顶部的状态栏、底部或侧面的导航栏以及应用界面。有些应用会拥有更多或更少的层&#xff08;例如&#xff0c;默认主屏幕应用有一个单独的壁纸层&#xff0c;而全屏游戏可能会隐藏状态栏&#xff09;。…

棱形打印--进阶2(Java)

棱形打印 问题 * *** ***** ******* ********* ******* ***** *** * * * …

centos上搭建nginx视频点播服务器(nginx+vod+lua http发送鉴权消息)

需求背景&#xff1a;想着搭建一个视频点播服务器&#xff0c;最后选择了nginxvod的方案&#xff0c;用lua脚本写拉流鉴权&#xff0c;但是环境搭建过程中又发现nginxvodlua的环境并不是很容易搭建&#xff0c;是nginxlua的环境&#xff0c;手动搭建比较麻烦&#xff0c;但还是…

Numpy基础与实例——人工智能基础

文章目录一、Numpy概述1、优势2、numpy历史3、Numpy的核心&#xff1a;多维数组4、内存中的ndarray对象4.1 元数据&#xff08;metadata&#xff09;4.2 实际数据二、numpy基础1、 ndarray数组2、 arange、zeros、ones、zeros_like3、ndarray对象属性的基本操作3.1 修改数组维度…

羊了个羊游戏开发教程1:堆叠牌的拾取

本文首发于微信公众号&#xff1a; 小蚂蚁教你做游戏。欢迎关注领取更多学习做游戏的原创教程资料&#xff0c;每天学点儿游戏开发知识。嗨&#xff01;大家好&#xff0c;我是小蚂蚁。最近“羊了个羊”小游戏爆火。一下子让想做微信小游戏或者想学做微信小游戏的人多了很多&am…

Java Map集合

8 Map集合 HashMap: 元素按照键是无序&#xff0c;不重复&#xff0c;无索引&#xff0c;值不做要求 LinkedHashMap: 元素按照键是有序&#xff0c;不重复&#xff0c;无索引&#xff0c;值不做要求 8.1 Map集合概述和特点 Map集合是一种双列集合&#xff0c;每个元素包含两个…

【C++】 C C++ 内存管理

文章目录&#x1f4d5; C、C 内存分布&#x1f4d5; C 内存管理方式1. 操作内置类型2. 操作自定义类型&#x1f4d5; operator new 与 operator delete&#x1f4d5; 定位 new&#x1f4d5; C、C 内存分布 C 和 C 的内存分布没什么区别&#xff0c;C 是基于 C 语言的&#xff…

腾讯xSRC[linux+docker]搭建教程

腾讯xSRC[linuxdocker]搭建教程 1.下载镜像 docker pull xsrc/xsrc:v1.0.12.启动镜像 1️⃣启动镜像 docker run -it -d --name xsrc_web -p 60080:80 -p 63306:3306 --privilegedtrue xsrc/xsrc:v1.0.1注意将3306端口映射到8806端口&#xff0c;以便于远程连接访问容器内数…

手写识别字体的步骤是什么?怎么识别图片中的文字?

手写识别字体的步骤是什么&#xff1f;怎么识别图片中的文字&#xff1f; 1. 打开信风工具网&#xff0c;点击拍照按钮&#xff0c;选择拍图识字模式&#xff0c;对准需要识别的文件进行拍摄&#xff61;在线工具地址&#xff1a; https://ocr.bytedance.zj.cn/image/ImageT…

VScode 自定义主题颜色

vscode其实已经有很多完善且好看的主题了&#xff0c;但我总觉得每一个主题对我来说&#xff0c;都有那么一点点不够完美&#xff0c;比如亮色的主题&#xff0c;颜色就没有深色主题那么好看&#xff0c;对比度高。 好不容易看到一个好看的主题吧&#xff0c;又觉得某一部分的…

2023213-popover弹窗框中的teleported属性--Element-plus踩坑日记

popover弹窗框中的teleported属性–Element plus踩坑日记 今天在做项目时&#xff0c;有一个地方用到了弹窗框&#xff0c;但是有需求需要修改弹窗的阴影部分 比如下方的 我想对阴影进行修改&#xff0c;但是很是纳闷&#xff0c;各种标签选择器都不生效&#xff0c;很奇怪。…