摘自《程序员代码面试指南》
题目:
给定数组 arr 和整数 num, 共返回有多少个⼦数组满⾜如下情况:
max(arr[i...j]) - min(arr[i...j]) <= num
max(arr[i...j])表示⼦数组 arr[i...j]中的最⼤值,min(arr[i...j])表示⼦数组arr[i...j]中的最小值。
题解:
区间最大最小值,立刻联想到单调栈(双端队列),不过稍微麻烦一些,需要在此基础上总结一些规律。
如果⼦数组 arr[i..j]满⾜条件, 即 max(arr[í.._i])-min(arr[i..j])<=num, 那么 arr[i..j]中的每⼀个⼦数组, 即 arr[k..l](i<=k<=|<=j)都满⾜条件 我们以⼦数组 arr[i..j-1]为例说明, arr[i..j-1]最⼤值只可能⼩于或等于arr[i..j]的最大值, arr[i..j-1]最小值只可能大于或等于 arr[i..j]的最小值, 所以 arr[i..j-|]必然满⾜条件, 同理, arr[i..j]中的每⼀个⼦数组都满⾜条件
如果⼦数组 arr[i..j]不 满⾜条件, 那 么 所有 包含 arr[i..j]的 ⼦数组, 即arr[k..l](k<=i<=j<=|)都不满⾜条件. 证明 过程同 第 ⼀个结论
也就是说,此问题还满足一个性质,那就是可以根据两端的下标范围确定满足条件的子数组个数,这一点很重要
Solution
#include <iostream> #include <vector> #include <deque> using namespace std; int maxMatchedArray(vector<int> &nums, int num){ deque<int> qmax, qmin; int n = nums.size(); int res = 0; int i = 0, j = 0; while (i < n){ while (j < n){ while (!qmin.empty() && nums[qmin.back()] >= nums[j]) qmin.pop_back(); qmin.push_back(j); while (!qmax.empty() && nums[qmax.back()] <= nums[j]) qmax.pop_back(); qmax.push_back(j); if (nums[qmax.front()] - nums[qmin.front()] > num) break; ++j; } if (qmin.front() == i) qmin.pop_front(); if (qmax.front() == i) qmax.pop_front(); res += j - i; //所有以arr[i]作为第一个元素的子数组,满足条件的数量为 j - i 个 ++i; } return res; } int main(){ vector<int> v{ 8,7,12,5,16,9,17,2,4,6}; int n = 3; cout << maxMatchedArray(v, n) << endl; system("pause"); return 0; }