代码随想录-算法训练营day13【栈与队列03:滑动窗口最大值、前K个高频元素、简化路径、总结】

代码随想录-035期-算法训练营【博客笔记汇总表】-CSDN博客

第五章 栈与队列part03今日内容: ● 239. 滑动窗口最大值
● 347.前 K 个高频元素
● 总结详细布置 239. 滑动窗口最大值 (一刷至少需要理解思路)之前讲的都是栈的应用,这次该是队列的应用了。本题算比较有难度的,需要自己去构造单调队列,建议先看视频来理解。 题目链接/文章讲解/视频讲解:https://programmercarl.com/0239.%E6%BB%91%E5%8A%A8%E7%AA%97%E5%8F%A3%E6%9C%80%E5%A4%A7%E5%80%BC.html 347.前 K 个高频元素  (一刷至少需要理解思路)大/小顶堆的应用, 在C++中就是优先级队列 本题是 大数据中取前k值 的经典思路,了解想法之后,不算难。题目链接/文章讲解/视频讲解:https://programmercarl.com/0347.%E5%89%8DK%E4%B8%AA%E9%AB%98%E9%A2%91%E5%85%83%E7%B4%A0.html  总结 栈与队列做一个总结吧,加油https://programmercarl.com/%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97%E6%80%BB%E7%BB%93.html  往日任务
● day 1 任务以及具体安排:https://docs.qq.com/doc/DUG9UR2ZUc3BjRUdY  
● day 2 任务以及具体安排:https://docs.qq.com/doc/DUGRwWXNOVEpyaVpG  
● day 3 任务以及具体安排:https://docs.qq.com/doc/DUGdqYWNYeGhlaVR6 
● day 4 任务以及具体安排:https://docs.qq.com/doc/DUFNjYUxYRHRVWklp 
● day 5 周日休息
● day 6 任务以及具体安排:https://docs.qq.com/doc/DUEtFSGdreWRuR2p4 
● day 7 任务以及具体安排:https://docs.qq.com/doc/DUElCb1NyTVpXa0Jj 
● day 8 任务以及具体安排:https://docs.qq.com/doc/DUGdsY2JFaFhDRVZH 
● day 9 任务以及具体安排:https://docs.qq.com/doc/DUHVXSnZNaXpVUHN4 
● day 10 任务以及具体安排:https://docs.qq.com/doc/DUElqeHh3cndDbW1Q 
●day 11 任务以及具体安排:https://docs.qq.com/doc/DUHh6UE5hUUZOZUd0 
●day 12 周日休息 

目录

0239_滑动窗口最大值

单调队列

解法一

解法二

单调栈

0347_前K个高频元素

0071_简化路径

总结


0239_滑动窗口最大值

单调队列

解法一

import java.util.*;class Solution0239 {public int[] maxSlidingWindow(int[] nums, int k) {//时间复杂度:O(n * k),超时!int res[] = new int[nums.length - k + 1], index = 0;for (int i = 0; i < nums.length - k + 1; i++) {int max = Integer.MIN_VALUE;//sum = 0for (int j = 0; j < k; j++) {//遍历滑动窗口//sum += nums[i + j];if (nums[i + j] > max) {max = nums[i + j];}}res[index++] = max;}return res;}public int[] maxSlidingWindow2(int[] nums, int k) {if (nums.length == 1) {return nums;}int len = nums.length - k + 1;//存放结果元素的数组int[] res = new int[len];int num = 0;//自定义队列MyQueue0239 myQueue = new MyQueue0239();//先将前k的元素放入队列for (int i = 0; i < k; i++) {myQueue.add(nums[i]);}res[num++] = myQueue.peek();for (int i = k; i < nums.length; i++) {//滑动窗口移除最前面的元素,移除是判断该元素是否放入队列myQueue.poll(nums[i - k]);//滑动窗口加入最后面的元素myQueue.add(nums[i]);//记录对应的最大值res[num++] = myQueue.peek();}return res;}
}//解法一
//自定义数组
class MyQueue0239 {Deque<Integer> deque = new LinkedList<>();//弹出元素时,比较当前要弹出的数值是否等于队列出口的数值,如果相等则弹出//同时判断队列当前是否为空void poll(int val) {if (!deque.isEmpty() && val == deque.peek()) {deque.poll();}}//添加元素时,如果要添加的元素大于入口处的元素,就将入口元素弹出//保证队列元素单调递减//比如此时队列元素3,1,2将要入队,比1大,所以1弹出,此时队列:3,2void add(int val) {while (!deque.isEmpty() && val > deque.getLast()) {deque.removeLast();}deque.add(val);}//队列队顶元素始终为最大值int peek() {return deque.peek();}
}

解法二

//解法二
//利用双端队列手动实现单调队列
/*** 用一个单调队列来存储对应的下标,每当窗口滑动的时候,直接取队列的头部指针对应的值放入结果集即可* 单调队列类似 (tail -->) 3 --> 2 --> 1 --> 0 (--> head) (右边为头结点,元素存的是下标)*/
class Solution0239_2 {public int[] maxSlidingWindow(int[] nums, int k) {ArrayDeque<Integer> deque = new ArrayDeque<>();int n = nums.length;int[] res = new int[n - k + 1];int idx = 0;for (int i = 0; i < n; i++) {//根据题意,i为nums下标,是要在[i - k + 1, i]中选到最大值,只需要保证两点//1.队列头结点需要在[i - k + 1, i]范围内,不符合则要弹出while (!deque.isEmpty() && deque.peek() < i - k + 1) {deque.poll();}//2.既然是单调,就要保证每次放进去的数字要比末尾的都大,否则也弹出while (!deque.isEmpty() && nums[deque.peekLast()] < nums[i]) {deque.pollLast();}deque.offer(i);//因为单调,当i增长到符合第一个k范围的时候,每滑动一步都将队列头节点放入结果就行了if (i >= k - 1) {res[idx++] = nums[deque.peek()];}}return res;}
}

单调栈

ArrayDeque<Integer> deque = new ArrayDeque<>();

在 Java 中,Deque 接口提供了几种方法来操作双端队列(或称为栈):

  1. peekFirst(): 返回双端队列的第一个元素(栈顶元素)的值,但不移除它。
  2. peekLast(): 返回双端队列的最后一个元素(栈底元素)的值,但不移除它。
  3. pollFirst(): 移除并返回双端队列的第一个元素(栈顶元素)的值。
  4. pollLast(): 移除并返回双端队列的最后一个元素(栈底元素)的值。
  5. offerFirst(i) : 用于将元素 i 添加到双端队列的开头(队列头部)。
  6. offerLast(i): 将元素 i 添加到双端队列的末尾(栈顶)。

这些方法允许你以栈的方式操作双端队列。

class Solution0239_3 {public int[] maxSlidingWindow(int[] nums, int k) {if (nums == null || nums.length == 0) return new int[0];int n = nums.length;int[] result = new int[n - k + 1];Deque<Integer> stack = new LinkedList<>();for (int i = 0; i < n; i++) {//如果当前窗口的最左侧元素已经不在窗口内,则移除if (!stack.isEmpty() && stack.peekFirst() < i - k + 1) {stack.pollFirst();}//保持单调递减栈while (!stack.isEmpty() && nums[i] >= nums[stack.peekLast()]) {stack.pollLast();}//将当前元素的索引加入栈中stack.offerLast(i);//当窗口大小达到 k 时,将窗口最大值添加到结果数组中if (i >= k - 1) {result[i - k + 1] = nums[stack.peekFirst()];}}return result;}
}

0347_前K个高频元素

import java.util.*;class Solution0347 {public int[] topKFrequent(int[] nums, int k) {Map<Integer, Integer> map = new HashMap<>();//key:数字,value:出现到频次for (int x : nums) {map.put(x, map.getOrDefault(x, 0) + 1);}ArrayList<Map.Entry<Integer, Integer>> list = new ArrayList<>(map.entrySet());Collections.sort(list, (a, b) -> {//根据value进行排序return a.getValue() - b.getValue();});int[] ints = new int[k];for (int i = 0; i < k; i++) {ints[i] = list.get(i).getKey();}return ints;}
}/*Comparator接口说明:* 返回负数,形参中第一个参数排在前面;* 返回正数,形参中第二个参数排在前面** 对于队列:排在前面意味着往队头靠* 对于堆(使用PriorityQueue实现):从队头到队尾按从小到大排就是最小堆(小顶堆),*                               从队头到队尾按从大到小排就是最大堆(大顶堆)---> 队头元素相当于堆的根节点* */
class Solution0347_2 {//解法1:基于大顶堆实现public int[] topKFrequent1(int[] nums, int k) {Map<Integer, Integer> map = new HashMap<>();//key为数组元素值,val为对应出现次数for (int num : nums) {map.put(num, map.getOrDefault(num, 0) + 1);}//在优先队列中存储二元组(num, cnt),cnt表示元素值num在数组中的出现次数//出现次数按从队头到队尾的顺序是从大到小排,出现次数最多的在队头(相当于大顶堆)PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2) -> pair2[1] - pair1[1]);for (Map.Entry<Integer, Integer> entry : map.entrySet()) {//大顶堆需要对所有元素进行排序pq.add(new int[]{entry.getKey(), entry.getValue()});}int[] ans = new int[k];for (int i = 0; i < k; i++) { //依次从队头弹出k个,就是出现频率前k高的元素ans[i] = pq.poll()[0];}return ans;}//解法2:基于小顶堆实现public int[] topKFrequent2(int[] nums, int k) {Map<Integer, Integer> map = new HashMap<>(); //key为数组元素值,val为对应出现次数for (int num : nums) {map.put(num, map.getOrDefault(num, 0) + 1);}//在优先队列中存储二元组(num, cnt),cnt表示元素值num在数组中的出现次数//出现次数按从队头到队尾的顺序是从小到大排,出现次数最低的在队头(相当于小顶堆)PriorityQueue<int[]> pq = new PriorityQueue<>((pair1, pair2) -> pair1[1] - pair2[1]);for (Map.Entry<Integer, Integer> entry : map.entrySet()) { //小顶堆只需要维持k个元素有序if (pq.size() < k) { //小顶堆元素个数小于k个时直接加pq.add(new int[]{entry.getKey(), entry.getValue()});} else {if (entry.getValue() > pq.peek()[1]) { //当前元素出现次数大于小顶堆的根结点(这k个元素中出现次数最少的那个)pq.poll(); //弹出队头(小顶堆的根结点),即把堆里出现次数最少的那个删除,留下的就是出现次数多的了pq.add(new int[]{entry.getKey(), entry.getValue()});}}}int[] ans = new int[k];for (int i = k - 1; i >= 0; i--) { //依次弹出小顶堆,先弹出的是堆的根,出现次数少,后面弹出的出现次数多ans[i] = pq.poll()[0];}return ans;}
}class Solution0347_3 {public int[] topKFrequent(int[] nums, int k) {// 优先级队列,为了避免复杂 api 操作,pq 存储数组// lambda 表达式设置优先级队列从大到小存储 o1 - o2 为从小到大,o2 - o1 反之PriorityQueue<int[]> pq = new PriorityQueue<>((o1, o2) -> o1[1] - o2[1]);int[] res = new int[k]; // 答案数组为 k 个元素Map<Integer, Integer> map = new HashMap<>(); // 记录元素出现次数for (int num : nums) map.put(num, map.getOrDefault(num, 0) + 1);for (Map.Entry<Integer, Integer> x : map.entrySet()) { // entrySet 获取 k-v Set 集合// 将 kv 转化成数组int[] tmp = new int[2];tmp[0] = x.getKey();tmp[1] = x.getValue();pq.offer(tmp);// 下面的代码是根据小根堆实现的,我只保留优先队列的最后的k个,只要超出了k我就将最小的弹出,剩余的k个就是答案if (pq.size() > k) {pq.poll();}}for (int i = 0; i < k; i++) {res[i] = pq.poll()[0]; // 获取优先队列里的元素}return res;}
}

0071_简化路径

import java.util.ArrayDeque;
import java.util.Deque;class Solution0071 {public String simplifyPath(String path) {String[] names = path.split("/");Deque<String> stack = new ArrayDeque<String>();for (String name : names) {if ("..".equals(name)) {if (!stack.isEmpty()) {stack.pollLast();}} else if (name.length() > 0 && !".".equals(name)) {stack.offerLast(name);}}StringBuffer ans = new StringBuffer();if (stack.isEmpty()) {ans.append('/');} else {while (!stack.isEmpty()) {ans.append('/');ans.append(stack.pollFirst());}}return ans.toString();}
}

总结

ヾ(◍°∇°◍)ノ゙

可以出一道面试题:栈里面的元素在内存中是连续分布的么?

这个问题有两个陷阱:

  • 陷阱1:栈是容器适配器,底层容器使用不同的容器,导致栈内数据在内存中不一定是连续分布的。
  • 陷阱2:缺省情况下,默认底层容器是deque,那么deque在内存中的数据分布是什么样的呢? 答案是:不连续的,下文也会提到deque。

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

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

相关文章

Qt使用miniblink第三方浏览器模块

文章目录 一、前言二、miniblink简介三、miniblink使用四、运行效果五、工程结构 一、前言 本文取自刘典武大师&#xff1a;Qt编写地图综合应用58-兼容多浏览器内核 用Qt做项目过程中&#xff0c;遇到需要用到浏览器控件的项目&#xff0c;可能都会绕不开一个问题&#xff0c;那…

【Web】VS Code 插件

专栏文章索引&#xff1a;Web 有问题可私聊&#xff1a;QQ&#xff1a;3375119339 目录 一、安装步骤 二、插件 1.Chinese (Simplified) (简体中文) 2.open in browser 3.vscode-icons 4.Live Server 5.Live Server Preview 6.翻译(英汉词典) 一、安装步骤 点击 “扩…

创纪录的里程碑!光镊阵列捕获逾6,000中性原子,量子计算再达新高

论文链接&#xff1a; https://arxiv.org/abs/2403.12021 2024年3月18日&#xff0c;研究人员成功开发出一种大规模光镊阵列&#xff0c;能够在12,000个位点上捕获超过6,100个中性原子&#xff0c;同时在几个关键性能指标上达到新的高度&#xff1a; 1&#xff09;相干时间达到…

javascript设计模式----访问者模式

访问者模式:针对于对象结构中的元素,定义在不改变改对象的前提下访问结构中元素的新方法。 解决事件回调函数中对改元素的访问问题。 实现的核心,调用call或者apply 场景:用dom2级事件为页面中的元素绑定事件 var bindEvent = function(dom,type,fn){if(dom.addEventListe…

新零售门店、商品、会员管理指标体系总览

新零售&#xff0c;旨在打破传统零售业的边界&#xff0c;引入先进科技和数字化手段&#xff0c;通过整合线上线下渠道&#xff0c;全面提升用户体验&#xff0c;并实现更智能、高效、个性化的零售运营模式。这一模式不仅仅关注销售产品&#xff0c;更注重构建全方位的购物生态…

《中医临床诊疗术语》数据库

最新版的《中医临床诊疗术语》于2023年3月17日由国家中医药管理局提出的&#xff0c;由国家市场监督管理总局和国家标准化管理委员会共同发布。新版的修订是为落实相关政策文件要求&#xff0c;推进中医医疗服务规范化、标准化管理&#xff0c;提高中医医疗服务标准化水平和管理…

asyncio异步编程

参考视频&#xff1a;02 协程_哔哩哔哩_bilibili 1.协程&#xff1a;&#xff08;不是计算机中真实存在的&#xff0c;人为创造出的概念&#xff09;&#xff0c;也可称为微线程。 本质是用一个线程在一段代码中来会切换游走的线程&#xff0c;是一种用户态内的上下文切换技术…

中科驭数:DPU是构建高效智算中心基础设施的必选项

4 月 15 日&#xff0c;在江苏省未来网络创新研究院、网络通信与安全紫金山实验室举办的“2024智算网络技术与应用创新峰会”上&#xff0c;中科驭数作为DPU算力基础设施领军企业&#xff0c;受邀出席本次峰会。中科驭数产品运营部副总经理曹辉先生在《基于DPU的高效智算中心算…

OpenCV与AI深度学习 | 2024年AI初学者需要掌握的热门技能有哪些?

本文来源公众号“OpenCV与AI深度学习”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;2024年AI初学者需要掌握的热门技能有哪些&#xff1f; 0 导 读 本文主要介绍2024年AI初学者需要掌握的热门技能。 1 前 言 人工智能无疑是技…

数据分析业务——二八定律

二八定律 转载&#xff1a;百度百科 二八定律也叫巴莱多定律&#xff0c;是19世纪末20世纪初意大利经济学家巴莱多发明的。他认为&#xff0c;在任何一组东西中&#xff0c;最重要的只占其中一小部分&#xff0c;约20%&#xff0c;其余80%的尽管是多数&#xff0c;却是次要的&…

基于java+springboot+vue实现的智慧党建系统(文末源码+Lw+ppt)23-58

摘 要 当今社会进入了科技进步、经济社会快速发展的新时代。国际信息和学术交流也不断加强&#xff0c;计算机技术对经济社会发展和人民生活改善的影响也日益突出&#xff0c;人类的生存和思考方式也产生了变化。传统智慧党建管理采取了人工的管理方法&#xff0c;但这种管…

openGauss学习笔记-264 openGauss性能调优-TPCC性能调优测试指导-BIOS配置

文章目录 openGauss学习笔记-264 openGauss性能调优-TPCC性能调优测试指导-BIOS配置264.1 恢复BIOS出厂设置264.2 修改相关BIOS设置264.3 重启操作系统 openGauss学习笔记-264 openGauss性能调优-TPCC性能调优测试指导-BIOS配置 本章节主要介绍openGauss数据库内核基于鲲鹏服务…

repo 管理多个git仓库

当repo init时&#xff0c;执行的repo是环境变量里面默认的repo&#xff0c;这个repo只是单纯一个几百行的Python脚本 而不是完整的repo-project&#xff0c;所以要先去网络远端sync完整的repo-project&#xff0c; 因为repo也是开源项目&#xff0c;设计者出于维护和使用体验&…

BTI功能验证与异常解析

BTI分支目标识别精讲与实践系列 思考 1、什么是代码重用攻击&#xff1f;什么是ROP攻击&#xff1f;区别与联系&#xff1f; 2、什么是JOP攻击&#xff1f;间接分支跳转指令&#xff1f; 3、JOP攻击的缓解技术&#xff1f;控制流完整性保护&#xff1f; 4、BTI下的JOP如何…

【MATLAB源码-第53期】m代码基于粒子群算法(PSO)的三维路径规划,显示最优路径和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 粒子群算法&#xff08;Particle Swarm Optimization&#xff0c;简称PSO&#xff09;是一种模拟鸟群觅食行为的启发式优化方法。以下是其详细描述&#xff1a; 基本思想&#xff1a; 鸟群在寻找食物时&#xff0c;每只鸟都…

机器学习实验------随机森林

第1关&#xff1a;Bagging 任务描述 本关任务&#xff1a;补充 python 代码&#xff0c;完成 BaggingClassifier 类中的 fit 和 predict 函数。请不要修改 Begin-End 段之外的代码。 import numpy as np from collections import Counter from sklearn.tree import DecisionT…

【开发篇】十三、JVM基础参数设置与垃圾回收器的选择

文章目录 1、-Xmx 和 –Xms2、-XX:MaxMetaspaceSize 和 –XX:MetaspaceSize3、-Xss4、不建议改的参数5、其他参数6、选择GC回收器的调试思路7、CMS的并发模式失败现象的解决8、调优案例 GC问题解决方式&#xff1a; 优化JVM基础参数&#xff0c;避免频繁Full GC减少对象的产生…

ADB的基本语法及常用命令

学习网址 ADB命令的基本语法如下&#xff1a; adb [-d|-e|-s <serialNumber>] <command> 如果有多个设备/模拟器连接&#xff0c;则需要为命令指定目标设备。 参数及含义如下&#xff1a; 常用命令如下&#xff1a; 1. 启动ADB服务 adb start-server 2. 停止…

JavaScript入门--数组

JavaScript入门--数组 前言数组的操作1、在数组的尾部添加元素2、删除数组尾部的元素&#xff0c;也就是最后一个元素3、删除头部第一个元素4、在数组的前面添加元素 小案例5、数组的翻转6、数组的排序7、数组的合并8、数组的切片 前言 JS中的数组类似于python中的列表&#x…

人工智能揭示矩阵乘法的新可能性

人工智能揭示矩阵乘法的新可能性 数学家酷爱漂亮的谜题。当你尝试找到最有效的方法时&#xff0c;即使像乘法矩阵&#xff08;二维数字表&#xff09;这样抽象的东西也会感觉像玩一场游戏。这有点像尝试用尽可能少的步骤解开魔方——具有挑战性&#xff0c;但也很诱人。除了魔方…