【LeetCode】239. 滑动窗口最大值 数组指针的解决方案(C++ 56ms)

maxSlidingWindow

  • 题目链接:https://leetcode.com/problems/sliding-window-maximum/
  • 滑动窗口的题目,比较常见,因为微信蓝桥的文章开始研究,以为比较简单,解答是用的双端数列,我觉得不好,做了一晚上没有成功,今天理一下,还是有点意思,总结一下。2019-4-28
  • 入坑链接:https://mp.weixin.qq.com/s?__biz=MzA4ODIwMDUyNw==&mid=2652995782&idx=1&sn=550c3be98f99466fc34b1a6339a50a35&chksm=8bf8e4e6bc8f6df06a7eaf57b91c69d5f33f202faa10d0b9e9b2d0002efc1e2a9454cd43ff7b&scene=0&xtrack=1&key=06b9089f8b38a19d800023d8397188132b106e6dfff5de26bb6476956221bc9c4b2a1130e1d7093096b76fe8610d3c6a2bac2c13e12eaf884fad188d98e8142b12956c414422c1a5c9b27d10312c91f4&ascene=1&uin=ODQ2NzM1MDM0&devicetype=Windows+10&version=62060739&lang=zh_CN&pass_ticket=EvA%2BVSbpVxTEzKttd%2FcdlRP1OV7q10cfIHPXOWNbW3Ubnoz9nNnVvBWwU8wp3pze

题目要求

Given an array nums, there is a sliding window of size k which is moving from the very left of the array to the very right. You can only see the k numbers in the window. Each time the sliding window moves right by one position. Return the max sliding window.

解题要点

主要思路:

  1. 使用左右指针来模拟窗口,l和r是左右边界。使用m记录窗口中最大值的索引。
  2. 窗口不断滚动,l和r逐渐增加,当m不在[l, r ]这个区间时,就重新确定m的位置。当窗口拓展,新的元素加入时,需要计较原来窗口的最大值和新加入的元素,使m指向其中较大的一个。记录每一个窗口中的最大值即可。
  3. 这样的开销在于findMax函数,貌似会耽误很多时间,导致O(n^2)的复杂度。但是findMax和外层的遍历是互补的,findMax的最差情况(最后一个是最大值)会为外层的遍历节省k-1次。反之,倘若原数组是降序排列的,每一次窗口拓展都需要频繁调用findMax,那么findMax很快就可以得到结果,效率不会变差。

实现细节

  1. 窗口大小和数组进行比较,处理0数组和大窗口的问题。
    1. 0数组直接返回引用
    2. 大窗口,在0到n中只找一遍
  2. 之后初始化,r = k -1,l=0,m=-1,当m在[l, r ]区间时,窗口滑动,如果nums[r] 大于 nums[m],则m=r。当m不在[l, r ]这个区间时,在区间内findMax,返回值为最大值的索引,即为m。
  3. 保存每次窗口中的最大值nums[m],即可。

答案

答案1

int findMax(vector<int>& nums, int start, int end)
{
	int index = start;
	for (int i = start; i < end; i++)
	{
		if (nums[i] > nums[index])
		{
			index = i;
		}
	}
	return index;
}
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
	int l = 0, r =0,m=0,index=0;
	vector <int> ans;
	int n = nums.size();
	int * tmp = new int[n + 5];
	if (n == 0)
		return ans;
	if (n <= k)
	{
		int index = findMax(nums, 0, n);
		ans.push_back(nums[index]);
		return ans;
	}
	
	m = -1;
	for (r = k -1,l=0; r < n; r++,l++)
	{
		if(!(m<=r && m>=l))
			m = findMax(nums, l,r+1);
		if (nums[r] >= nums[m])
			m = r;
		tmp[index++] = nums[m];
	}
	vector <int> ans1(tmp,tmp+index);
	return ans1;
}
Runtime: 56 ms, faster than 98.83% of C++ online submissions for Sliding Window Maximum.
Memory Usage: 12.9 MB, less than 92.20% of C++ online submissions for Sliding Window Maximum.

答案2

  1. 实际上l基本没用,由于向右滚动,可以进行压缩,保证nums[l]是每一个窗口的最大值,每次都读取窗口左边界的值
  2. 每次窗口拓展的时候,如果超过了k,重新确定l的位置。否则比较nums[r]和nums[l],使得l始终为窗口的最大值索引
#include <cstdio>
#include <vector>
using namespace std;

int findMax(vector<int>& nums, int start, int end)
{
	int index = start;
	for (int i = start; i < end; i++)
	{
		if (nums[i] > nums[index])
		{
			index = i;
		}
	}
	return index;
}


vector<int> maxSlidingWindow(vector<int>& nums, int k) {
	int l = 0, r = 0;
	vector <int> ans;
	int n = nums.size();
	if (k == 1)
		return nums;
	if (n == 0)
		return ans;
	if (n <= k)
	{
		int index = findMax(nums, 0, n);
		ans.push_back(nums[index]);
		return ans;
	}
	l = findMax(nums, 0, k);
	ans.push_back(nums[l]);
	r = k - 1;
	for (int i = k ; i < n; i++)
	{
		
		r++;
		if (r >= n)
			break;
		if (r - l == k)
		{
			l++;
			l = findMax(nums, l, r + 1);
		}
		if (nums[r] >= nums[l])
		{
			l = r;
		}
		ans.push_back(nums[l]);
	}
	return ans;
}

结果

Runtime: 56 ms, faster than 98.83% of C++ online submissions for Sliding Window Maximum.
Memory Usage: 13.1 MB, less than 72.88% of C++ online submissions for Sliding Window Maximum.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值