代码随想录算法训练营第十天 | 239.滑动窗口最大值、347.前K个高频元素
代码随想录算法训练营第十天 | 239.滑动窗口最大值、347.前K个高频元素
文章目录
- 代码随想录算法训练营第十天 | 239.滑动窗口最大值、347.前K个高频元素
- 1 LeetCode 239.滑动窗口最大值
- 2 LeetCode 347.前K个高频元素
1 LeetCode 239.滑动窗口最大值
题目链接:https://leetcode.cn/problems/sliding-window-maximum/description/
给你一个整数数组
nums,有一个大小为k的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的k个数字。滑动窗口每次只向右移动一位。返回 滑动窗口中的最大值 。
示例 1:
输入:nums = [1,3,-1,-3,5,3,6,7], k = 3 输出:[3,3,5,5,6,7] 解释: 滑动窗口的位置 最大值 --------------- ----- [1 3 -1] -3 5 3 6 7 31 [3 -1 -3] 5 3 6 7 31 3 [-1 -3 5] 3 6 7 51 3 -1 [-3 5 3] 6 7 51 3 -1 -3 [5 3 6] 7 61 3 -1 -3 5 [3 6 7] 7示例 2:
输入:nums = [1], k = 1 输出:[1]提示:
1 <= nums.length <= 105-104 <= nums[i] <= 1041 <= k <= nums.length
这道题目很难,对于第一次做的人来说,力扣上面的困难题目还是很有挑战性的,这道题目考察的就是单调队列的应用,很多人可能会想到优先级队列,在脑袋里面大概想了一下可能觉得可以,但其实不行,因为优先级队列会打乱顺序,就比如nums = [1,3,-1,-3,5,3,6,7], k = 3,刚开始排序[3,1,-1],没问题,最大值在队头,然后我们还需要向右移动,然后弹出1,可是优先级队列中1在队列的中间,无法弹出,所以就无法实现找滑动窗口中的最大值。
我们可以利用双端队列来构造一个单调队列来解决这道题目。
- 创建一个双端队列(Deque)来存储元素的索引,而不是存储元素的值,这是因为我们需要在队列中比较索引,以确定元素是否在窗口内,创建一个空列表
result来存储最终的结果。 - 我们开始遍历数组
nums,逐个处理每个元素。 - 在每次遍历之前,检查队列的首元素是否已经超出了当前窗口的范围,如果队列的首元素对应的索引小于当前索引减去窗口大小
k加 1,就将队列的首元素弹出(出队),因为它不再在窗口内。 - 继续检查队列中的元素,如果队列中的元素对应的数组值小于等于当前元素的值,将它们从队列的尾部弹出,因为它们不可能是窗口内的最大值,我们的目标是确保队列中的元素是按照递减顺序排列的,以便窗口内的最大值总是在队列的首元素位置。
- 将当前元素的索引添加到队列的尾部。
- 当我们遍历到达满足窗口大小的位置(即当前索引大于等于
k-1),就可以获取窗口内的最大值。这是因为我们确保队列的首元素是当前窗口内的最大值的索引。将队列的首元素对应的值添加到结果列表result中。 - 继续遍历整个数组,重复上述步骤直到遍历完成。
- 最后返回结果列表
result,其中包含了每个窗口内的最大值。
思路清楚,下面我们来写一下代码:
(1)Python版本代码
from collections import deque
class Solution:def maxSlidingWindow(self, nums, k):result = [] # 用于存储最终的滑动窗口最大值window = deque() # 创建一个双端队列用于存储窗口内的元素索引n = len(nums)for i in range(n): if window and window[0] < i - k + 1: # 移除队列中超出窗口范围的索引window.popleft()while window and nums[i] >= nums[window[-1]]: # 移除队列中比当前元素小的元素索引window.pop()window.append(i) # 将当前元素的索引加入队列if i >= k - 1: # 当窗口形成后,将队列的首元素对应的值加入结果列表result.append(nums[window[0]])return result
下面是代码随想录中的代码:
from collections import dequeclass MyQueue: #单调队列(从大到小def __init__(self):self.queue = deque() #这里需要使用deque实现单调队列,直接使用list会超时#每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。#同时pop之前判断队列当前是否为空。def pop(self, value):if self.queue and value == self.queue[0]:self.queue.popleft()#list.pop()时间复杂度为O(n),这里需要使用collections.deque()#如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。#这样就保持了队列里的数值是单调从大到小的了。def push(self, value):while self.queue and value > self.queue[-1]:self.queue.pop()self.queue.append(value)#查询当前队列里的最大值 直接返回队列前端也就是front就可以了。def front(self):return self.queue[0]class Solution:def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:que = MyQueue()result = []for i in range(k): #先将前k的元素放进队列que.push(nums[i])result.append(que.front()) #result 记录前k的元素的最大值for i in range(k, len(nums)):que.pop(nums[i - k]) #滑动窗口移除最前面元素que.push(nums[i]) #滑动窗口前加入最后面的元素result.append(que.front()) #记录对应的最大值return result
(2)C++版本代码
#include <vector>
#include <deque>class Solution {
public:std::vector<int> maxSlidingWindow(std::vector<int>& nums, int k) {std::vector<int> result;std::deque<int> window;int n = nums.size();for (int i = 0; i < n; ++i) {// 移除队列中超出窗口范围的索引if (!window.empty() && window.front() < i - k + 1) {window.pop_front();}// 移除队列中比当前元素小的元素索引while (!window.empty() && nums[i] >= nums[window.back()]) {window.pop_back();}// 将当前元素的索引加入队列window.push_back(i);// 当窗口形成后,将队列的首元素对应的值加入结果列表if (i >= k - 1) {result.push_back(nums[window.front()]);}}return result;}
};
- 时间复杂度: O(n)
- 空间复杂度: O(k)
后续研究了一下,发现这题可以用优先队列实现的,也就是用大根堆实现,下面直接给出我学到的代码,感兴趣的朋友可以研究一下:
#include <vector> #include <queue> #include <utility>class Solution { public:std::vector<int> maxSlidingWindow(std::vector<int>& nums, int k) {std::vector<int> result;std::priority_queue<std::pair<int, int>> pq; // 存储元素值和索引的大根堆for (int i = 0; i < nums.size(); ++i) {while (!pq.empty() && pq.top().second <= i - k) {pq.pop(); // 移除不在窗口内的元素}pq.push({nums[i], i});if (i >= k - 1) {result.push_back(pq.top().first); // 将窗口的最大值加入结果列表}}return result;} };此时的时间复杂度到达了O(log k)。
2 LeetCode 347.前K个高频元素
题目链接:https://leetcode.cn/problems/top-k-frequent-elements/description/
给你一个整数数组
nums和一个整数k,请你返回其中出现频率前k高的元素。你可以按 任意顺序 返回答案。示例 1:
输入: nums = [1,1,1,2,2,3], k = 2 输出: [1,2]示例 2:
输入: nums = [1], k = 1 输出: [1]提示:
1 <= nums.length <= 105k的取值范围是[1, 数组中不相同的元素的个数]- 题目数据保证答案唯一,换句话说,数组中前
k个高频元素的集合是唯一的**进阶:**你所设计算法的时间复杂度 必须 优于
O(n log n),其中n是数组大小。
一般来说,题目出现统计元素频率以及找出频率前K个元素,我们就要想到map和堆的结合运用,其中map很适合用来统计元素频率,然后堆也很适合维系一个单调的K个元素的排序集合,然后对数据集不断地遍历,不断地更新维系地集合。
堆有两种形式,一种是大顶堆(也叫大根堆),另一种是小顶堆(也叫小根堆),相信学过408的朋友对堆这种数据结构应该不陌生,那么在本题中我们应该选择哪一种形式的堆呢?答案是小顶堆,为什么?因为如果选择大顶堆,那么我们在每次加入元素之后,判断堆中元素是否超过K个(因为我们只需要维系K个元素即可),如果超过我们就需要将堆顶元素弹出,但是大顶堆的话此时堆顶元素是最大值,最后遍历完我们其实收集的是前K个低频元素,刚好相反了,因此我们就需要选择小顶堆来实现(可以手动画图感受一下,堆也就是一颗完全二叉树)。
(1)Python版本代码
import heapqclass Solution:def topKFrequent(self, nums, k):# 统计每个元素的频率hashmap = {}for num in nums:hashmap[num] = hashmap.get(num, 0) + 1# 使用最小堆来存储所有元素heap = []for key, value in hashmap.items():heapq.heappush(heap, (value, key)) # 存储频率和元素# 弹出除了频率最高的k个元素之外的所有元素while len(heap) > k:heapq.heappop(heap)# 提取结果return [key for _, key in heap]if __name__ == '__main__':s = Solution()nums = list(map(int, input().split()))k = int(input())print(s.topKFrequent(nums, k))
(2)C++版本代码
#include <iostream>
#include <vector>
#include <queue>
#include <unordered_map>
#include <utility>
#include <functional>class Solution {
public:std::vector<int> topKFrequent(std::vector<int>& nums, int k) {// 统计每个元素的频率std::unordered_map<int, int> hashmap;for (int num : nums) {++hashmap[num];}// 使用最小堆来存储所有元素std::priority_queue<std::pair<int, int>, std::vector<std::pair<int, int>>, std::greater<std::pair<int, int>>> heap;for (auto& it : hashmap) {heap.push({it.second, it.first});if (heap.size() > k) {heap.pop();}}std::vector<int> result;while (!heap.empty()) {result.push_back(heap.top().second);heap.pop();}return result;}
};int main() {Solution s;std::vector<int> nums;int num;while (std::cin >> num) {nums.push_back(num);if (std::cin.peek() == '\n') break;}int k;std::cin >> k;std::vector<int> result = s.topKFrequent(nums, k);for (int i : result) {std::cout << i << " ";}std::cout << std::endl;return 0;
}
- 时间复杂度:O(nlogn)
- 空间复杂度:O(n)
相关文章:
代码随想录算法训练营第十天 | 239.滑动窗口最大值、347.前K个高频元素
代码随想录算法训练营第十天 | 239.滑动窗口最大值、347.前K个高频元素 文章目录 代码随想录算法训练营第十天 | 239.滑动窗口最大值、347.前K个高频元素1 LeetCode 239.滑动窗口最大值2 LeetCode 347.前K个高频元素 1 LeetCode 239.滑动窗口最大值 题目链接:https…...
【Godot4自学手册】第五节用GDScript语言让主人公动起来
GDScript 是Godot自带的编程语言,用于编写游戏逻辑,它是一种高级面向对象的指令式编程语言,使用渐进类型,专为 Godot 构建。在这一小节里,我将自学用GDScript语言控制主人公的行走和攻击。 一、给Player节点添加GDScr…...
被问到Tomcat是什么该怎么回答?他还有一个好帮手JDK你知道吗?
目录 Tomcat简介: 使用建议: Tomcat好帮手---JDK Tomcat和JDK的关系 安装JDK 1.打开浏览器输入网址 Oracle | Cloud Applications and Cloud Platform 进入Oracle官网 2、在官网首页菜单栏,点击产品,在硬件和软件中找到Java࿰…...
【Web前端实操11】定位实操_照片墙(无序摆放)
设置一个板块,将照片随意无序摆放在墙上,从而形成照片墙。本来效果应该是很唯美好看的,就像这种,但是奈何本人手太笨,只好设置能达到照片墙的效果就可。 代码如下: <!DOCTYPE html> <html lang&…...
图像处理------调整色调
什么是色调? 色调,在画面上表现思想、感情所使用的色彩和色彩的浓淡。分为暖色调和冷色调。 from cv2 import destroyAllWindows, imread, imshow, waitKey#创建棕褐色色调 def make_sepia(img, factor: int):pixel_h, pixel_v img.shape[0], img.shap…...
【操作系统】实验七 显示进程列表
🕺作者: 主页 我的专栏C语言从0到1探秘C数据结构从0到1探秘Linux 😘欢迎关注:👍点赞🙌收藏✍️留言 🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要&…...
[实战]加密传输数据解密
前言 下面将分享一些实际的渗透测试经验,帮助你应对在测试中遇到的数据包内容加密的情况。我们将以实战为主,技巧为辅,进入逆向的大门。 技巧 开局先讲一下技巧,掌握好了技巧,方便逆向的时候可以更加快速的找到关键函数…...
yarn install 报错 证书过期 Certificate has expired
“Certificate has expired” 的意思是证书已过期。这通常是指数字证书在其有效期限之前已经失效了。数字证书通常用于加密和保护网络通信,以及验证网站的身份。如果证书已经过期,那么使用该证书的网站或服务可能会受到安全威胁。为了保证安全࿰…...
多流转换 (分流,合流,基于时间的合流——双流联结 )
目录 一,分流 1.实现分流 2.使用侧输出流 二,合流 1,联合 2,连接 三,基于时间的合流——双流联结 1,窗口联结 1.1 窗口联结的调用 1.2 窗口联结的处理流程 2,间隔联结 2.1 间隔联…...
Linux破解密码
破解root密码(Linux 7) 1、先重启——e 2、Linux 16这一行 末尾加rd.break(不要回车)中断加载内核 3、再ctrlx启动,进入救援模式 4、mount -o remount,rw /sysroot/——(mount挂载 o——opti…...
ABAP 批导demo调用SM30表维护demo
ABAP 批导demo&调用SM30表维护demo &--------------------------------------------------------------------- *& Report ZPP036 &--------------------------------------------------------------------- *& &-----------------------------------…...
Mysql 文件导入与导出
i/o 一、导出(mysqldump)<一>、导出sql文件<二>、导出csv文件 二、导入(load)三、常见报错The Mysql server is running with the --secure-file-priv option so it cannot execute this statement 一、导出(mysqldump) <一>、导出sql文件 1、整库 mysqld…...
《每天十分钟》-红宝书第4版-迭代器与生成器
理解迭代 计数循环就是一种最简单的迭代 for (let i 1; i < 10; i) { console.log(i); }迭代之前需要事先知道如何使用数据结构。数组中的每一项都只能先通过引用取得数组对象,然后再通过[]操作符取得特定索引位置上的项。这种情况并不适用于所有数据结构。遍…...
1、【vue篇】vue框架快速上手
注意事项: methods必须要加s 导入vue:<script src"https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>导入Axios:<script src"https://unpkg.com/axios/dist/axios.min.js"></script> 简单Vue程序…...
Unity 编辑器篇|(九)编辑器美化类( GUIStyle、GUISkin、EditorStyles) (全面总结 | 建议收藏)
目录 1. GUIStyle1.1 参数总览1.2 样式代码 2. GUISkin2.1 参数总览2.2 创建自定义Skin 3. EditorStyles2.1 参数总览1.2 反射获取所有EditorStyles 1. GUIStyle GUIStyle是一个用于定制GUI控件样式的类,它包含了控件的外观属性,如字体、颜色、背景等。…...
Spring Boot Starters
Spring Boot Starters 概述 Spring Boot Starters是一系列为特定应用场景预设的依赖管理和自动配置方案。每个Starter都是为了简化特定类型的项目构建和配置。例如,spring-boot-starter-web是为创建基于Spring MVC的Web应用程序而设计的。 Starter的结构 一个典型…...
Qt防止创建窗口抢焦点
问题是,当我在 Qt 中打开一个新窗口时,它会自动窃取前一个应用程序的焦点。 有什么办法可以防止这种情况发生吗? setAttribute(Qt::WA_ShowWithoutActivating);这会强制窗口不激活。即使有Qt::WindowStaysOnTopHint flag 出处: S…...
shared_ptr 与 unique_ptr 的转换 笔记
推荐B站文章: 6.shared_ptr与unique_ptr_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV18B4y187uL?p6&vd_sourcea934d7fc6f47698a29dac90a922ba5a3我的往期文章: 独占指针:unique_ptr 与 函数调用-CSDN博客https://blog.csdn.n…...
python windows和linux 文件同步
在Python中,可以使用paramiko库来实现Windows和Linux之间的文件同步。paramiko是一个用于SSH连接的Python库,可以用于在Windows和Linux之间进行文件传输。 以下是一个简单的示例代码,演示如何使用paramiko库在Windows和Linux之间同步文件&am…...
【数据结构】72变的双端队列
双端队列 前言一、双端队列1.1 双端队列的定义1.2 输入受限的双端队列1.3 输出受限的双端队列1.5 输入输出都受限的双端队列1.6 小结 二、双端队列的使用2.1 双端队列的出队序列——暴力求解2.1.1 栈的出栈序列2.1.2 输入受限的双端队列2.1.3 输出受限的双端队列2.1.4 输入输出…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...
高频面试之3Zookeeper
高频面试之3Zookeeper 文章目录 高频面试之3Zookeeper3.1 常用命令3.2 选举机制3.3 Zookeeper符合法则中哪两个?3.4 Zookeeper脑裂3.5 Zookeeper用来干嘛了 3.1 常用命令 ls、get、create、delete、deleteall3.2 选举机制 半数机制(过半机制࿰…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
MySQL 8.0 事务全面讲解
以下是一个结合两次回答的 MySQL 8.0 事务全面讲解,涵盖了事务的核心概念、操作示例、失败回滚、隔离级别、事务性 DDL 和 XA 事务等内容,并修正了查看隔离级别的命令。 MySQL 8.0 事务全面讲解 一、事务的核心概念(ACID) 事务是…...
