题目链接: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"); } }