跳转至

双指针

前置知识

基础算法

what

双指针是一种简单而又灵活的技巧和思想,单独使用可以轻松解决一些特定问题,和其他算法结合也能发挥多样的用处。

双指针顾名思义,就是同时使用两个指针,在序列、链表结构上指向的是位置,在树、图结构中指向的是节点,通过或同向移动,或相向移动来维护、统计信息。

why

维护区间信息

如果不和其他数据结构结合使用,双指针维护区间信息的最简单模式就是维护具有一定单调性,新增和删去一个元素都很方便处理的信息,就比如正数的和、正整数的积等等。

(“维护”的意思是使用某些数据结构记录一些信息,使其符合一定的性质,并且对这些信息进行增删改查)

双指针算法本质是使用队列维护一个符合条件的区间。

右指针增加相当于入队,左指针增加相对于出队。

一般情况下,这个区间是一个左闭右开区间,[l, r)

How

例题,A-B 数对 - 洛谷

题意,给出一串正整数数列以及一个正整数C,要求计算出所有满足 AB=C 的数对的个数

#include<bits/stdc++.h>

using namespace std;

const int N = 2e5 + 10;

int a[N], n, c;

int main(){
    cin >> n >> c;
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);

    sort(a + 1, a + n + 1);

    int l = 1, r = 1;
    long long sum = 0;

    // a[l] - a[i] < c, 跳出循环的时候,l是第一个满足a[l] - a[i] >= c的
    // a[r] - a[i] <= c, 跳出循环的时候,r是第一个不满足a[r] - a[i] <= c的
    // 那么此时,r - 1是最后一个满足式子 a[r] - a[i] <=  c的
    // 满足特定条件的区间是 [l, r)
    for (int i = 1; i <= n; i++) {
        while (a[l] - a[i] < c && l <= n) l++;
        while (a[r] - a[i] <= c && r <= n) r++;

        if (a[l] - a[i] == c && a[r - 1] - a[i] == c) {
            sum += r - l;
            // printf("---%d %d %d\n", a[i], l, r);
        }
    }

    cout << sum << '\n';

    return 0;
}

例题,逛画展 - 洛谷

题意,找到一个区间覆盖了1~m的所有数,区间尽可能短

#include <bits/stdc++.h>

using namespace std;

const int N = 1e6 + 10;

int a[N], n, m;
map<int, int> mp;

// [l, r)
int main() {
    cin >> n >> m;
    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);

    int l = 1, r = 1, num = 0;
    int ret = 2e9, x, y;
    while (l <= r && r <= n + 1) {
        if (num < m) {
            r++;
            mp[a[r - 1]]++;
            if (mp[a[r - 1]] == 1) num++;
        }
        else {
            if (r - l < ret) {
                ret = r - l;
                x = l, y = r - 1;
            }

            mp[a[l]]--;
            if (mp[a[l]] == 0) num--;
            l++;
        }
    }

    cout << x << ' ' << y << '\n';

    return 0;
}

题单

P1102 A-B 数对

P1638 逛画展

POJ3061 Subsequenc

CF252C Points on Line(难)(题解,ZqIceberg:CF252C_Points on Line

POJ2566 Bound Found(难)

HDU6295 回文树(难)

HDU5746 Memento Mori(难)

总结

双指针,又名尺取法,英文two pointers。虽然在CCF大纲中我没有找到这个,但在算法比赛中是高频算法。

参考

双指针 - OI Wiki

《深入浅出程序设计竞赛》进阶篇