给你一个整数数组 nums ,和一个表示限制的整数 limit,请你返回最长连续子数组的长度,该子数组中的任意两个元素之间的绝对差必须小于或者等于 limit 。
如果不存在满足条件的子数组,则返回 0 。
示例 1:
1 | 输入:nums = [8,2,4,7], limit = 4 |
示例 2:
1 | 输入:nums = [10,1,2,4,7,2], limit = 5 |
示例 3:
1 | 输入:nums = [4,2,2,2,4,4,2,2], limit = 0 |
双指针~
我们开设两个指针 $l,r$,先移动 $r$ 指针,并记录区间 $[l,r]$ 内的最大值 $mx$ 和最小值 $mn$,显然当 $mx-mn\leq limit$ 时,区间长度就是答案;当条件不满足时,我们只需要固定 $r$ 指针,移动 $l$ 指针即可,即必须缩短区间长度以满足题目所给条件,但是我们移动指针的过程中要同时改变最大最小值,显然光开两个变量是不够的,我提供了两种方法:
- 开一个大根堆 $mx$ 和小根堆 $mn$,显然堆顶就是我们要找的最大最小值,维护两个堆即可
- C++里面有一个强大的数据结构 $multiset$(同样是最容易被忽视的数据结构),这个数据结构自动排序且支持元素重复,显然 $multiset$ 的迭代器指向的开头和末尾就是我们要找的最大最小值
下面两段代码分别对应第一种和第二种方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23class Solution {
public:
int longestSubarray(vector<int> &nums, int limit) {
int l = 0, r = 0, ans = 0;
unordered_map<int, int> cnt;
priority_queue<int, vector<int>, less<>> mx;
priority_queue<int, vector<int>, greater<>> mn;
while (r < nums.size()) {
cnt[nums[r]]++;
mx.emplace(nums[r]);
mn.emplace(nums[r]);
while (mx.top() - mn.top() > limit) {
cnt[nums[l]]--;
while (!cnt[mx.top()]) mx.pop();
while (!cnt[mn.top()]) mn.pop();
l++;
}
ans = max(ans, r - l + 1);
r++;
}
return ans;
}
};
1 | class Solution { |