题目描述:
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
思路分析:
思路一:自己首先想到的算法是比较朴素的,首先对于第一个窗口利用遍历的方式找到这个窗口的最大值,并且保留当前的最大值以及其索引值。之后每一次以步长1进行移位,将当前值与保留的最大值进行比较,若大于这个最大值,则更新最大值和对应的最大值索引。否则需要进行一个判断,判断之前的最大值与当前值的索引之差是否小于滑动窗口的大小(即最大值是否包含在滑动窗口中),若是则当前的最大值即为这个窗口的最大值,否则需要再次通过遍历的方式查找当前窗口的最大值,并更新最大值和最大值索引。这个方法的复杂度会达到O(nk),其中k表示窗口的个数。
思路二:
参考了一下其他方法,大部分都利用到了双向队列这个数据结构来做这道题。思想实际是比较类似的。整个过程维护了从头到尾递减的一个双向队列,但这里存储的是对应元素的索引值(同样是为了通过索引求和滑动窗口的相对位置关系)即队头元素最大,依次递减。同样是首先求第一个滑动窗口的最大值,对于每一个进队的元素,和队尾元素进行比较,清空所有比当前元素小的元素,再将当前元素进队,这样一个滑动窗口大小的迭代完成后。队首的元素即为这个滑动窗口的最大值。接下来对于后续的窗口,同样清空小于当前元素的队尾元素,接下来需要进行判断,当前的队首元素可能为这个窗口的最大值,当当前的队首元素的索引值与当前元素索引值相差大于滑动窗口大小时,那么这个队首就不可能为当前窗口的最大值,将它从队首删除。直到与上述条件相悖,那么当前的队首元素即为这个窗口的最大值。
代码:
1 class Solution { 2 public: 3 vector<int> maxInWindows(const vector<int>& num, unsigned int size) 4 { 5 vector<int> MaxVal; 6 if(num.size()<size || size==0) 7 return MaxVal; 8 int max = INT_MIN; 9 int max_idx = -1; 10 for(int i=0; i<size; i++) 11 { 12 if(max < num[i]) 13 { 14 max = num[i]; 15 max_idx = i; 16 } 17 } 18 MaxVal.push_back(max); 19 for(int i = size; i<num.size(); i++) 20 { 21 if(num[i] > max) 22 { 23 MaxVal.push_back(num[i]); 24 max = num[i]; 25 max_idx = i; 26 } 27 else if(i-max_idx < size) 28 { 29 MaxVal.push_back(max); 30 } 31 else 32 { 33 max = INT_MIN; 34 for(int j = 0; j<size; j++) 35 { 36 if(max < num[i-j]) 37 { 38 max = num[i-j]; 39 max_idx = i-j; 40 } 41 } 42 MaxVal.push_back(max); 43 } 44 } 45 return MaxVal; 46 } 47 };
1 class Solution { 2 public: 3 vector<int> maxInWindows(const vector<int>& num, unsigned int size) 4 { 5 vector<int> MaxVal; 6 if(num.size()<size || size==0) 7 return MaxVal; 8 deque<int> index; 9 for(int i=0; i<size; i++) 10 { 11 // 若队列非空,且当前要添加的数大于队列的最小值,则删除队列中的最小值 12 while(!index.empty() && num[i] >= num[index.back()]) 13 { 14 index.pop_back(); 15 } 16 index.push_back(i); 17 } 18 for(int i=size; i<num.size(); i++) 19 { 20 MaxVal.push_back(num[index.front()]); 21 while(!index.empty() && num[i] >= num[index.back()]) 22 { 23 index.pop_back(); 24 } 25 while(!index.empty() && (i-index.front())>=size) 26 { 27 index.pop_front(); 28 } 29 index.push_back(i); 30 } 31 MaxVal.push_back(num[index.front()]); 32 return MaxVal; 33 } 34 };