双指针,离散化和区间合并
双指针
时间复杂度普遍为O(n)
for (int i = 0, j = 0; i < n; i ++ )
{
while (j < i && check(i, j)) j ++ ;
// 具体问题的逻辑
}
例题
#include
#include
#include
using namespace std;
const int N = 30;
int a[N];
string s;
int main() {
cin >> s;
int res = 0;
for (int i = 0, j = 0; i < s.size(); i ++ ) {
a[s[i] - 'a'] ++;
while (j < i && a[s[i] - 'a'] > 1) {
a[s[j] - 'a'] --;
j ++;
}
res = max(res, i - j + 1);
}
cout << res << endl;
return 0;
}
常见问题分类:
(1) 对于一个序列,用两个指针维护一段区间
(2) 对于两个序列,维护某种次序,比如归并排序中合并两个有序序列的操作
离散化
对于大范围,但是数据少的题,如果直接开相应数组大小的话,时空可能会爆掉,所以可以将无限的空间,映射成有限的空间,一一对应。
思路是:
1.先排序
2.再删除重复元素
3.最后就是索引元素离散化后对应的值。
vector alls; // 存储所有待离散化的值
sort(alls.begin(), alls.end()); // 将所有值排序
alls.erase(unique(alls.begin(), alls.end()), alls.end()); // 去掉重复元素
// 二分求出x对应的离散化的值
int find(int x) // 找到第一个大于等于x的位置
{
int l = 0, r = alls.size() - 1;
while (l < r)
{
int mid = l + r >> 1;
if (alls[mid] >= x) r = mid;
else l = mid + 1;
}
return r + 1; // 映射到1, 2, ...n
}
区间合并
1.先对区间头进行排序
2.然后持续更新尾部
// 将所有存在交集的区间合并
void merge(vector &segs)
{
vector res;
sort(segs.begin(), segs.end());
int st = -2e9, ed = -2e9;
for (auto seg : segs)
if (ed < seg.first)//如果没有交集
{
if (st != -2e9) res.push_back({st, ed});//加入第一段区间
st = seg.first, ed = seg.second;//更新头尾值
}
else ed = max(ed, seg.second);//更新最大的尾值
if (st != -2e9) res.push_back({st, ed});
segs = res;
}