Clasa a XII-a · Tehnici avansate: doi pointeri, căutare binară pe răspuns, stive monotoneRead in English

Doi pointeri — perechi cu suma x într-un vector sortat în C++

În engleză: Two pointers: pairs with sum x in a sorted array

O(n)C++1767 de linii2 exemple

Ideea

Vectorul are n valori distincte, în ordine strict crescătoare. Vrem perechile de poziții i < j cu a[i] + a[j] = x. În loc să încercăm toate cele n * (n-1) / 2 perechi, punem un indice st la început și unul dr la sfârșit. Dacă a[st] + a[dr] < x, suma trebuie să crească, deci st++; dacă e mai mare, dr--; dacă e egală, am găsit o pereche și mutăm ambii indici. Fiecare pas mută cel puțin un indice spre celălalt, deci sunt cel mult n pași. Afișăm numărul perechilor, apoi perechile.

Descrierea în engleză

The array has n distinct values in strictly increasing order. We want the position pairs i < j with a[i] + a[j] = x. Instead of trying all n * (n-1) / 2 pairs, we put an index st at the beginning and one dr at the end. If a[st] + a[dr] < x, the sum must grow, so st++; if it is larger, dr--; if it is equal, we found a pair and move both indices. Every step moves at least one index towards the other, so there are at most n steps. We print the number of pairs, then the pairs.

Complexitate
O(n)
Clasa
Clasa a XII-a (Grade 12)

Exemple

Exemplul 1

Intrare

8 10
1 2 3 4 6 7 8 9

Ieșire așteptată

4
1 9
2 8
3 7
4 6
Exemplul 2

Intrare

3 100
1 2 3

Ieșire așteptată

0

Codul C++

Codul complet, cu comentarii în română. Îl poți modifica liber și îl poți reseta oricând.

doi-pointeri-perechi-suma-x.cpp
/*
 * Titlu: Doi pointeri — perechi cu suma x într-un vector sortat
 * Clasa: 12
 * Capitol: Tehnici avansate: doi pointeri, căutare binară pe răspuns, stive monotone
 * Descriere: Vectorul are n valori distincte, în ordine strict crescătoare. Vrem
 *            perechile de poziții i < j cu a[i] + a[j] = x. În loc să încercăm
 *            toate cele n * (n-1) / 2 perechi, punem un indice st la început și
 *            unul dr la sfârșit. Dacă a[st] + a[dr] < x, suma trebuie să crească,
 *            deci st++; dacă e mai mare, dr--; dacă e egală, am găsit o pereche
 *            și mutăm ambii indici. Fiecare pas mută cel puțin un indice spre
 *            celălalt, deci sunt cel mult n pași. Afișăm numărul perechilor, apoi
 *            perechile.
 * Complexitate: O(n)
 *
 * Exemplu
 * Intrare:
 * 8 10
 * 1 2 3 4 6 7 8 9
 * Ieșire:
 * 4
 * 1 9
 * 2 8
 * 3 7
 * 4 6
 *
 * Exemplu
 * Intrare:
 * 3 100
 * 1 2 3
 * Ieșire: 0
 */
#include <iostream>
#include <utility>
#include <vector>
using namespace std;

int main()
{
    int n;
    long long x;
    cin >> n >> x;
    vector<long long> a(n);
    for (int i = 0; i < n; i++)
        cin >> a[i];

    vector<pair<long long, long long>> perechi;
    int st = 0, dr = n - 1;
    while (st < dr)
    {
        long long s = a[st] + a[dr];
        if (s < x)
            st++;
        else if (s > x)
            dr--;
        else
        {
            perechi.push_back({a[st], a[dr]});
            st++;
            dr--;
        }
    }
    cout << perechi.size() << '\n';
    for (auto &p : perechi)
        cout << p.first << ' ' << p.second << '\n';
    return 0;
}

Rulează pe un g++ adevărat (C++17, -O2) prin Compiler Explorer. Programele trebuie să se termine repede: există o limită de timp.