1. 程式人生 > 其它 >雙指標,離散化和區間合併

雙指標,離散化和區間合併

雙指標

時間複雜度普遍為O(n)

for (int i = 0, j = 0; i < n; i ++ )
{
    while (j < i && check(i, j)) j ++ ;

    // 具體問題的邏輯
}

例題

#include <iostream>
#include <cstring>
#include <algorithm>
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<int> 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<PII> &segs)
{
    vector<PII> 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;
}