[程序员代码面试指南] 最大值减去最小值小于或等于num的子数组数量
题目描述:
给定数组arr和整数num,返回共有多少个子数组满足如下情况:
max(arr[i..j])-min(arr[i..j])<=num
分析:
- 利用滑动窗口进行计算,
[i..j]
用两个指针i
j
表示,其子数组. - 用两个双端数组分别维护这个窗口内的最大值和最小值
- 从数组arr的每个位置开始扩张(max-min<=num),直至不能扩张.此时,满足条件的子数组数量为 j-i;
- 不满足条件呢,需要窗口左移即
i++
. 然后更新一下两个双端队列
实现:
int getNum(vector<int> arr, int num) {
if (arr.size() == 0)
return 0;
int res = 0;
deque<int> qMin;
deque<int> qMax;
int i = 0;
int j = 0;
while (i < arr.size()) {
while (j < arr.size()) {
// 大于等于arr[j],则不可能成为最小值,所以要pop掉
while (!qMin.empty() && arr[qMin.back()] >= arr[j]) {
qMin.pop_back();
}
qMin.push_back(j);
// 小于等于arr[j],则不可能成为最大值,所以要pop掉
while (!qMax.empty() && arr[qMax.back()] <= arr[j]) {
qMax.pop_back();
}
qMax.push_back(j);
// 不满足条件则break,计算子数组个数
if (arr[qMax.front()] - arr[qMin.front()] > num) {
break;
}
j++;
}
res += j - i;
// 更新qMin和qMax 窗口是否过期的检测
if (qMin.front() == i) {
qMin.pop_front();
}
if (qMax.front() == i) {
qMax.pop_front();
}
}
return res;
}
体会:
- 动态维护一个窗口.可以使用双端队列
dequeue
- 窗口是否过期的检测