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

Stiva monotonă — următorul element mai mare în C++

În engleză: Monotonic stack: the next greater element

O(n)C++1753 de linii2 exemple

Ideea

Pentru fiecare a[i] căutăm prima valoare strict mai mare aflată în dreapta lui (sau -1). Ținem o stivă cu pozițiile care încă „așteaptă” un element mai mare; valorile lor sunt descrescătoare de la bază spre vârf. Când vine a[i], toate pozițiile din vârf cu valoare mai mică și-au găsit răspunsul: îl notăm și le scoatem. Apoi punem i în stivă. Pozițiile rămase la final nu au un element mai mare. Fiecare poziție intră și iese din stivă cel mult o dată.

Descrierea în engleză

For every a[i] we look for the first strictly greater value to its right (or -1). We keep a stack with the positions still 'waiting' for a greater element; their values decrease from the bottom to the top. When a[i] arrives, all positions on top with a smaller value have found their answer: we record it and pop them. Then we push i. The positions left at the end have no greater element. Every position is pushed and popped at most once.

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

Exemple

Exemplul 1

Intrare

8
4 5 2 25 7 8 1 9

Ieșire așteptată

5 25 25 -1 8 9 9 -1
Exemplul 2

Intrare

4
5 5 3 1

Ieșire așteptată

-1 -1 -1 -1

Codul C++

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

stiva-monotona-urmatorul-mai-mare.cpp
/*
 * Titlu: Stiva monotonă — următorul element mai mare
 * Clasa: 12
 * Capitol: Tehnici avansate: doi pointeri, căutare binară pe răspuns, stive monotone
 * Descriere: Pentru fiecare a[i] căutăm prima valoare strict mai mare aflată în
 *            dreapta lui (sau -1). Ținem o stivă cu pozițiile care încă „așteaptă”
 *            un element mai mare; valorile lor sunt descrescătoare de la bază spre
 *            vârf. Când vine a[i], toate pozițiile din vârf cu valoare mai mică
 *            și-au găsit răspunsul: îl notăm și le scoatem. Apoi punem i în stivă.
 *            Pozițiile rămase la final nu au un element mai mare. Fiecare poziție
 *            intră și iese din stivă cel mult o dată.
 * Complexitate: O(n)
 *
 * Exemplu
 * Intrare:
 * 8
 * 4 5 2 25 7 8 1 9
 * Ieșire: 5 25 25 -1 8 9 9 -1
 *
 * Exemplu
 * Intrare:
 * 4
 * 5 5 3 1
 * Ieșire: -1 -1 -1 -1
 */
#include <iostream>
#include <stack>
#include <vector>
using namespace std;

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

    stack<int> st; // poziții, cu valori descrescătoare spre vârf
    for (int i = 0; i < n; i++)
    {
        while (!st.empty() && a[st.top()] < a[i])
        {
            rasp[st.top()] = a[i];
            st.pop();
        }
        st.push(i);
    }
    for (int i = 0; i < n; i++)
        cout << rasp[i] << (i + 1 < n ? ' ' : '\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.