【deque】滑动窗口、双端队列解决数组问题
所属头文件 <deque>
常用操作:
back()返回尾部元素;
front()返回头部元素;
push_back()尾部插入元素;
pop_bakc()尾部删除元素;
push_front()头部插入元素;
pop_front()头部删除元素;
问题1:求滑动窗口的最大值(《剑指offer面试题65》)
描述:给定一个数组和滑动窗口的大小,找出所有滑动窗口里的最大值。
示例:数组{2, 3, 4, 2, 6, 2, 5} 窗口大小为 3,一共有7-3+1=5个滑动窗口,返回这些窗口最大值的数组{4, 4, 6, 6, 6}
方法:生成一个双端队列deque,里面存储可能成为滑动窗口最大值在数组中的下标。
vector<int> getMax(const vector<int> &arr, int size){ vector<int> res; if (arr.size() == 0 || size <= 0){ return res; } deque<int> index; int i = 0; while (i < arr.size()){ while (!index.empty() && arr[index.back()] <= arr[i]){ index.pop_back(); } index.push_back(i); if (!index.empty() && index.front() == (i - size)){ index.pop_front();//不属于当前窗口 } if (i >= size - 1){ res.push_back(arr[index.front()]); } i++; } return res; }
问题2:给定一个数组,找出最大值与最小值之差小于等于给定数num的子数组的个数。(牛客左程云《程序员面试代码指南》)
示例:给定数组{5, 2, 6, 3, 4, 1},num = 3,符合条件的子数组分别为{5} {5, 2} {2} {6} {6, 3} {6, 3, 4} {3} {3, 4} {3, 4, 1} {4} {4, 1} {1}返回数值12
方法:生成两个双端队列qmax, qmin,第一层while循环i,满足条件的将i作为起始元素的子数组;第二层while循环,满足条件的将j作为尾元素的子数组。每次内while循环结束,结果res += j - i;
qmax维护窗口子数组最大值在原数组中的下标;
qmin维护窗口子数组最小值在原数组中的下标。
窗口在动态发生变化,qmax和qmin的元素也在发生变化。
1 int getNum(int arr[], int len, int num){ 2 if (arr == NULL || len < 1 ||num < 0) 3 return 0; 4 int res = 0; 5 deque<int> qmax; 6 deque<int> qmin; 7 int i = 0; 8 int j = 0; 9 while (i < len){ 10 while (j < len){ 11 while (!qmax.empty() && arr[qmax.back()] <= arr[j]){ 12 qmax.pop_back(); 13 } 14 qmax.push_back(j); 15 while (!qmin.empty() && arr[qmin.back()] >= arr[j]){ 16 qmin.pop_back(); 17 } 18 qmin.push_back(j); 19 if (arr[qmax.front()] - arr[qmin.front()] > num){ 20 break; 21 } 22 j++; //j一直在变大,不回退 23 } 24 if (qmax.front() == i){ 25 qmax.pop_front(); //不属于以i+1开头的窗口,弹出 26 } 27 if (qmin.front() == i){ 28 qmin.pop_front(); //不属于以i+1开头的窗口,弹出 29 } 30 res += j - i; 31 i++; //i一直在变大,不回退 32 } 33 return res; 34 }