剑指offer系列53:滑动窗口的最大值
分两步:
首先找到窗口内的内容,然后找到窗口内的最大值。
1 class Solution { 2 public: 3 vector<int> maxInWindows(const vector<int>& num, unsigned int size) 4 { 5 vector<int> re; 6 7 int len = num.size(); 8 if (size == 0 || len == 0 || size > len) 9 return re; 10 //找到这几个数 11 for (int i = 0; i <= len - size; i++) 12 { 13 14 re.push_back(findbig(num, size,i)); 15 } 16 return re; 17 //求这几个数中的最大值 18 } 19 int findbig(const vector<int>& num, unsigned int size, unsigned int i) 20 { 21 int big = num[i]; 22 for (int k=i+1;k<i+size;k++) 23 { 24 if (num[k] > big) 25 big = num[k]; 26 } 27 return big; 28 } 29 };
上面的解法是我自己想的,看了剑指offer,这个题是在栈与队列这一节放的,也就是考点是栈与队列。用上面的方法做时间复杂度是O(nk),但是用队列的方法做复杂度可以到O(n),也就是说每次滑动窗口可以在O(1)里找到最大值。
很大提高了效率,那么怎么做呢。首先要想到队列这个数据结构,这个问题可以这样考虑:
1.设计一个队列放窗口内的内容,滑动一下窗口,往队列后面加元素,尾部插入
2.如果插入的这个结点比队列中原来的结点的尾部(不从头结点开始比较是因为头结点存的是最大的元素)的一些元素大,则删除这些尾部的元素,尾部删除
3.如果头结点存的值是已经滑过去的窗口的值,则删掉。头部删除
通过以上分析,头尾部都要操作,所以可以想到使用队列。
然后就是如何用队列实现这个问题:
1.对于不超过窗口长度的元素,只需要判断1,2
2.对于后面的元素,需要判断1,2,3
1 class Solution { 2 public: 3 vector<int> maxInWindows(const vector<int>& num, unsigned int size) 4 { 5 vector<int> re; 6 7 int len = num.size(); 8 if (size == 0 || len == 0 || size > len) 9 return re; 10 deque<int> aux; 11 for(int i=0;i<size;i++) 12 { 13 if (!aux.empty() && num[i] > num[aux.back()])//队列不为空并且来的元素大于以队列尾部的下标的值 14 aux.pop_back(); 15 aux.push_back(i);//队列中只存下标 16 } 17 for (int i = size; i < len; i++) 18 { 19 re.push_back(num[aux.front()]); 20 while(!aux.empty() && num[i] > num[aux.back()]) 21 aux.pop_back(); 22 23 24 if (!aux.empty() && aux.front() <= i - size)//队列最前面的值,也就是说最小的下标,不能是滑过的窗口元素 25 { 26 aux.pop_front(); 27 } 28 aux.push_back(i); 29 } 30 re.push_back(num[aux.front()]); 31 return re; 32 } 33 };
这个题首先要想到合适的数据结构,然后如何用这个合适的数据结构将这个题表达出来。都是需要考虑到的。