leetcode刷题/栈和队列 239. 滑动窗口最大值

这篇博客详细介绍了如何解决滑动窗口最大值的问题,通过两种不同的数据结构——优先队列和单调队列来实现。作者首先分享了自己的解题思路,尝试使用set和map但发现效率不高,随后介绍了优先队列和单调队列的工作原理,并提供了相应的代码实现。博客重点突出了这两种高效方法在处理此类问题时的优势。
摘要由CSDN通过智能技术生成

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       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

示例 2:

输入:nums = [1], k = 1
输出:[1]

示例 3:

输入:nums = [1,-1], k = 1
输出:[1,-1]

示例 4:

输入:nums = [9,11], k = 2
输出:[11]

示例 5:

输入:nums = [4,-2], k = 2
输出:[4]
解题思路:

自己想了一个多小时,想法是这样的

  • 想用set容器和pair一起完成,但是需要排序值,而且查找的时间复杂度太高,相当于暴力.
  • 那么就改用map,有类似于pair的功能.但是它不自带排序,总不能每次插入一个新的就排序一次,这也相当于暴力.

一直在两个容器间寻找如何做,直到后面实在没想到.看了题解才知道用优先队列和单调队列.

优先队列:

思想:利用优先队列顶部一定是最大值的性质.然后利用pair<值,下标>判断是否已经划出窗口

  • 首先压入前面K个元素,因为大顶堆性质,所有顶部一直是最大值.
  • 这时候遍历后续的数,每一次都需要判断顶部元素是否已经滑出窗口,即que.top().second <= i - k.
  • 每一次循环都添加最顶上元素到res结果数组中,直到循环结束即可

单调队列:

思想:单调队列利用deque容器可以删除尾部特点,可以保证每一次顶端都是最大值…

  • 如果要插入的值比尾部尾部下标对应的值大,那么就把尾部下标对应的值删除.
  • deque存储下标,如果超过界限,也就是q.front() <= i - k.那么久需要把这个下标去除.
  • 每一次循环都压入顶部下标对应的值
  • 循环遍历整个数组即可
优先队列代码:
class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
	vector<int> res;
	priority_queue<pair<int, int>> que;
	for (int i = 0; i < k; i++)
	{
		que.emplace(nums[i], i);
	}
	res.push_back(que.top().first);
	for (int i = k; i < nums.size(); i++)
	{
		que.emplace(nums[i], i);
		while (que.top().second <= i - k)
			que.pop();
		res.push_back(que.top().first);			
	}
	return res;
    }
};

单调队列代码:

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
	int n = nums.size();
	deque<int> q;
	for (int i = 0; i < k; ++i) {
		while (!q.empty() && nums[i] >= nums[q.back()]) {
			q.pop_back();
		}
		q.push_back(i);
	}

	vector<int> ans = { nums[q.front()] };
	for (int i = k; i < n; ++i) {
		while (!q.empty() && nums[i] >= nums[q.back()]) {
			q.pop_back();
		}
		q.push_back(i);
		while (q.front() <= i - k) {
			q.pop_front();
		}
		ans.push_back(nums[q.front()]);
	}
	return ans;
    }
};
总结:

两种想法都能完成,主要就是利用队列的思想.我做的时候一直想着的是优先队列,但是我是用STL做的,没有完成,看了题解才去看的优先队列…学的还不够多,不然应该要第一反应的

根据引用\[1\],可以使用暴力解法来求解滑动窗口最大值。具体的做法是,遍历数组,对于每个窗口,使用一个内部循环来找到窗口中的最大值,并将其存储在结果数组中。时间复杂度为O(n*k),其中n为数组长度,k为窗口大小。 根据引用\[2\],还可以使用队列来求解滑动窗口最大值。具体的做法是,使用一个双端队列来维护一个单调递减的窗口。遍历数组,对于每个元素,首先判断队头是否在滑动窗口范围内,如果不在,则将其从队头移除。然后,将当前元素与队尾元素比较,如果当前元素大于队尾元素,则将队尾元素移除,直到队列为空或者当前元素小于等于队尾元素。最后,将当前元素的索引插入队尾。如果滑动窗口的元素个数达到了k个,并且始终维持在窗口中,就将队头元素加入答案数组中。时间复杂度为O(n),其中n为数组长度。 综上所述,可以使用暴力解法或者使用队列来求解leetcode滑动窗口最大值。 #### 引用[.reference_title] - *1* *3* [leetcode239. 滑动窗口最大值](https://blog.csdn.net/kkkkuuga/article/details/124829581)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Leetcode#239. 滑动窗口最大值 (Java解法)](https://blog.csdn.net/paranior/article/details/114890555)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

公仔面i

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值