题目链接:http://leetcode.com/2011/01/sliding-window-maximum.html
咳咳,很长时间没有写博客了。各种各样的事情,前段时间又被各种打击。调整了好久,终于状态好多了,SO,步入正轨了。
题目分析:其实就是给定一个长度为N的数组,以k为窗口长度,窗口自左向右滑动,求出每一次窗口的最大值。
如果用蛮力的话,复杂度是O(KN),因为每一次取出k个元素,都要重新算最大值。其实仔细观察可以发现,每一次窗口的滑动都是从左边出一个数,右边进一个数,这样的操作规则不就是队列的特质么,从一边进,另一边出。这样就把问题转化成求大小为k的队列的最大值,每一次队列出一个、进一个。
这样的话,前面已经有一篇相关的博客,给出了在O(1)的时间内得到队列的最小值。这里一样的,就不废话了。至于网站上的那种解法,自我感觉没我的好,所以就不说什么了。转载注明出处。谢谢~
参考代码,核心函数就是用栈模拟队列进和出的操作。
//将value压入到DataStack之中,并更新MaxStack
void Push(int *DataStack, int *MaxStack, int &TopIndex, int Value)
{
assert(DataStack && MaxStack);
MaxStack[TopIndex + 1] = max(TopIndex > -1 ? MaxStack[TopIndex] : INT_MIN, Value);
DataStack[++TopIndex] = Value;
}
//元素出队列
void Pop()
{
if(OutTop < 0)//the out stack is empty
{
while(InTop > 0)//将InStack里面的元素压到OutStack中,保留最后一个,直接pop
{
Push(Out, OutMax, OutTop, In[InTop--]);
}
--InTop;
}
else
{
--OutTop;
}
}
//取得最大值
int GetMax()
{
return max(InTop > -1 ? InMax[InTop] : INT_MIN, OutTop > -1 ? OutMax[OutTop] : INT_MIN);
}
照旧,给出辅助函数和main函数的调用过程
#include<stdio.h>
#include<limits.h>
#include<assert.h>
const int MAX_N = 30;
int In[MAX_N];
int Out[MAX_N];
int InMax[MAX_N];
int OutMax[MAX_N];
int InTop = -1;
int OutTop = -1;
inline int max(const int a, const int b)
{
return a > b ? a : b;
}
void main()
{
int n,k,i;
int arr[MAX_N];
while(scanf("%d %d", &n, &k) != EOF)
{
for(i = 0; i < n; ++i)
{
scanf("%d", &arr[i]);
}
InTop = OutTop = -1;
for(i = 0; i < k; ++i)
{
Push(In, InMax, InTop, arr[i]);
}
printf("%d ", GetMax());
for(; i < n; ++i)
{
Push(In, InMax, InTop, arr[i]);
Pop();
printf("%d ", GetMax());
}
printf("\n");
}
}