算法练习第12天|● 239. 滑动窗口最大值● 347.前 K 个高频元素

2024-04-08 22:04

本文主要是介绍算法练习第12天|● 239. 滑动窗口最大值● 347.前 K 个高频元素,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

239.滑动窗口的最大值

力扣原题

题目描述:

给你一个整数数组 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]

思路分析:

        尝试使用单调队列来记录当前窗口中的最大值。如下图所示,单调队列的入队规则是如果入队的元素前面有比自己小的数,这些数全部被剔除。注意这里说的是剔除,而不是简单的出队。因为如果是单向队列的出队的话,那么单向队列在执行步骤四时可能需要先把数字3出队后才能继续通过出队的方式将-1剔除。这就导致最大值3从队列中消失了。

  所以为了更加方面的对多余元素进行剔除,单调队列在用STL容器中的双端deque进行实现,因为deque支持在队列两端进行入队、出队操作。如下图所示。这样在步骤二中的1、步骤四中的-1直接通过pop_back()进行剔除。很方便,而且还能保留最大值。

         综上所述,单调队列的目的就是为了维护窗口内最大的两个数。其结构大致长这样:

class MyQueue {
public:void push(int val) {}void pop(int val) {}int front() {return que.front();}
};

其中 push(int val) 表示val入队,它的规则是:如果val前面的元素比val小,那么就将这些数通过pop_back弹出,直到遇到比val大的数停止或队列为空停止。如上述的步骤二和步骤四。

pop(int val) 表示val出队,这种情况发生在滑动窗口向右移动的时候。如下图所示:

 窗口滑动之后,3不在是窗口内的数,所以需要使用pop_front将单调队列中的3弹出。这里的pop_front也体现出了deque的灵活性。

如果不满足 滑动窗口移动前最左端的值 = 单调队列最左(前)端的值 这个条件,则表明刚才窗口内的最大值还在移动口的窗口内,具体情况如下图所示:

综上所述,该单调队列的代码实现如下: 

class myQueue{  //自定义单调队列。从大到小排列,左边出队,右边入队public:deque<int> que;   //双端队列void push(int val){   //从队列右端输入数据。若输入的数据val比队列末尾的若干个数大,//则将这些数弹出.直到队列为空或val遇到比自身大的数while(!que.empty() && que.back() < val){que.pop_back();   //循环弹出比val小的数}//val入队que.push_back(val);}void pop(int val)  {//比较滑动窗口左端要弹出数值val是否是位于单调//队列左端的最大值,如果是,则弹出;如果不是,表明最大值这个数位于新的窗口内。if(!que.empty() && val == que.front()){que.pop_front();}}int front()  //单调队列最左端的值就是当前窗口的最大值{return que.front();}};

有了这样的单调队列,下面给出该题的解题代码:

class Solution {
private:class myQueue{  //自定义单调队列。从大到小排列,左边出队,右边入队public:deque<int> que;void push(int val){   //从队列右端输入数据。若输入的数据val比队列末尾的数大,则将该数弹出.直到队列为空或val遇到比自身大的数while(!que.empty() && que.back() < val){que.pop_back();   //循环弹出比val小的数}//val入队que.push_back(val);}void pop(int val)  //比较滑动窗口左端要弹出数值val是否是位于单调队列左端的最大值{if(!que.empty() && val == que.front()){que.pop_front();}}int front()  //当前窗口的最大值{return que.front();}};public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {myQueue que;vector<int> result;for(int i=0;i<k;i++)   //先将前k个数字入队{que.push(nums[i]);}//入队完成后,就只剩下最大的两个数result.push_back(que.front());  //记录当前窗口最大值for(int i = k; i<nums.size();i++)//然后从下标k开始进行窗口移动{//i-k和i的使用非常巧妙地模拟了窗口向右滑动的过程que.pop(nums[i-k]);  //窗口滑动先要执行是否pop出来最大值que.push(nums[i]);  //新元素入队,重新调整result.push_back(que.front()); // 记录新的最大值}return result;}
};

这篇关于算法练习第12天|● 239. 滑动窗口最大值● 347.前 K 个高频元素的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/886517

相关文章

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

SpringBoot启动报错的11个高频问题排查与解决终极指南

《SpringBoot启动报错的11个高频问题排查与解决终极指南》这篇文章主要为大家详细介绍了SpringBoot启动报错的11个高频问题的排查与解决,文中的示例代码讲解详细,感兴趣的小伙伴可以了解一... 目录1. 依赖冲突:NoSuchMethodError 的终极解法2. Bean注入失败:No qu

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

C++从序列容器中删除元素的四种方法

《C++从序列容器中删除元素的四种方法》删除元素的方法在序列容器和关联容器之间是非常不同的,在序列容器中,vector和string是最常用的,但这里也会介绍deque和list以供全面了解,尽管在一... 目录一、简介二、移除给定位置的元素三、移除与某个值相等的元素3.1、序列容器vector、deque

C++常见容器获取头元素的方法大全

《C++常见容器获取头元素的方法大全》在C++编程中,容器是存储和管理数据集合的重要工具,不同的容器提供了不同的接口来访问和操作其中的元素,获取容器的头元素(即第一个元素)是常见的操作之一,本文将详细... 目录一、std::vector二、std::list三、std::deque四、std::forwa

如何通过Golang的container/list实现LRU缓存算法

《如何通过Golang的container/list实现LRU缓存算法》文章介绍了Go语言中container/list包实现的双向链表,并探讨了如何使用链表实现LRU缓存,LRU缓存通过维护一个双向... 目录力扣:146. LRU 缓存主要结构 List 和 Element常用方法1. 初始化链表2.

golang字符串匹配算法解读

《golang字符串匹配算法解读》文章介绍了字符串匹配算法的原理,特别是Knuth-Morris-Pratt(KMP)算法,该算法通过构建模式串的前缀表来减少匹配时的不必要的字符比较,从而提高效率,在... 目录简介KMP实现代码总结简介字符串匹配算法主要用于在一个较长的文本串中查找一个较短的字符串(称为

通俗易懂的Java常见限流算法具体实现

《通俗易懂的Java常见限流算法具体实现》:本文主要介绍Java常见限流算法具体实现的相关资料,包括漏桶算法、令牌桶算法、Nginx限流和Redis+Lua限流的实现原理和具体步骤,并比较了它们的... 目录一、漏桶算法1.漏桶算法的思想和原理2.具体实现二、令牌桶算法1.令牌桶算法流程:2.具体实现2.1

Python使用Pandas对比两列数据取最大值的五种方法

《Python使用Pandas对比两列数据取最大值的五种方法》本文主要介绍使用Pandas对比两列数据取最大值的五种方法,包括使用max方法、apply方法结合lambda函数、函数、clip方法、w... 目录引言一、使用max方法二、使用apply方法结合lambda函数三、使用np.maximum函数

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定