维护满足某种条件的子数组,如果具有某种单调性,通常可以用双指针。
题目一
题目:题意:求最长的子串,且其最大值与最小值之差在[1,2]内,如果有多个,输出子串和最大的(华为机试题)
方法:
假设,我们已经有一组数字,我们继续添加数字时:当前这组数字的max-min要么增大,要么不变。而删除数字时,要么变小,要么不变(想想为什么)。可以用双指针来完成这个搜索的操作。
算法具体实现时,我们只要让l从1循环到n,r不断的向右跑以满足要求就可以了。求一堆数的最小最大值,并可以进行插入删除操作。这一部分用任意一种二叉搜索树就可以完成,比如红黑树。
typedef long long ll;
int longestSubarray(vector<int>& nums, int m1, int m2) {
multiset<int>ms;
int i = 0, j = 0, n = nums.size();
vector<ll>sum(n+1, 0);
for(int i = 1;i <= n;i++) {
sum[i] = sum[i-1] + nums[i-1];
}
ll len = 0, max_sum = 0;
while(j <= n) {
int cha = ms.empty() ? 0 : *(--ms.end()) - *ms.begin();
cout << i << " " << j << endl;
cout << "cha: " << cha << endl;
if(cha >= m1 && cha <= m2) { // 可行区间,更新答案
if(j-i >= len) {
len = j-i;
max_sum = max(max_sum, sum[j]-sum[i]);
}
}
if(j == n) break;
if(cha <= m2) {
ms.insert(nums[j]);
j++;
} else {
ms.erase(ms.find(nums[i]));
i++;
}
}
cout << "len: " << len << endl;
cout << "max_sum: " << max_sum << endl;
return len;
}
题目二
题目:LC1438. 绝对差不超过限制的最长连续子数组
方法:
一模一样,相当于上面的特例吧,m1=-limit, m2=limit
class Solution {
public:
int mylongestSubarray(vector<int>& nums, int m1, int m2) {
multiset<int>ms;
int i = 0, j = 0, n = nums.size();
int res = 0;
while(j <= n) {
int cha = ms.empty() ? 0 : *(--ms.end()) - *ms.begin();
if(cha >= m1 && cha <= m2) { // 可行区间,更新答案
res = max(res, j-i);
}
if(j >= n) break; // 最后一次j可能等于n
if(cha <= m2) {
ms.insert(nums[j]);
j++;
} else {
ms.erase(ms.find(nums[i]));
i++;
}
}
return res;
}
int longestSubarray(vector<int>& nums, int limit) {
return mylongestSubarray(nums, -limit, limit);
}
};
参考链接:C++ STL中平衡树在算法题目的应用