Pilas
| Fuente | Recurso | Notas |
|---|---|---|
| CPH | 4.5 - Stacks | descripción breve de las operaciones |
| CSA | Stack Introduction | Aplicación de matching de paréntesis |
Pilas
Una pila es una estructura de datos Last In First Out (LIFO: último en entrar, primero en salir) que soporta tres operaciones, todas en . Se puede pensar como una pila real de papeles.
C++
push: agrega un elemento al tope de la pilapop: saca un elemento del tope de la pilatop: obtiene el elemento del tope sin sacarlo
stack<int> s;
s.push(1); // [1]
s.push(13); // [1, 13]
s.push(7); // [1, 13, 7]
cout << s.top() << endl; // 7
s.pop(); // [1, 13]
cout << s.size() << endl; // 2Java
push: agrega un elemento al tope de la pilapop: saca un elemento del tope de la pilapeek: obtiene el elemento del tope sin sacarlo
Stack<Integer> s = new Stack<Integer>();
s.push(1); // [1]
s.push(13); // [1, 13]
s.push(7); // [1, 13, 7]
System.out.println(s.peek()); // 7
s.pop(); // [1, 13]
System.out.println(s.size()); // 2Python
Python no tiene un tipo pila integrado, pero una lista puede funcionar como pila.
list.append(): Agrega un elemento al final.list[-1]: Obtiene el último elemento sin sacarlo.list.pop(): Saca el último elemento y lo devuelve (pero no hace falta usar el valor devuelto).list.pop(n): Saca el -ésimo elemento, indexado desde cero. Nótese que sacar elementos es una operaciónO(n).
stack = [] # []
stack.append(1) # [1]
stack.append(2) # [1, 2]
stack.append(3) # [1, 2, 3]
v = stack[-1] # stack = [1, 2, 3] (sin cambios), v = 3
stack.pop() # [1, 2]
v = stack.pop() # stack = [1], v = 2
stack.append(4) # [1, 4]
v = stack.pop(0) # stack = [4], v = 1Aplicación: elemento menor más cercano
| Hecho | Fuente | Nombre | Dificultad | Tags | Solución |
|---|---|---|---|---|---|
| CSES | Nearest Smaller Values | Fácil | Stack | en el módulo |
Consideremos el siguiente problema:
Dado un arreglo de () enteros, para cada índice , hallar el índice más a la derecha tal que y .
| Fuente | Recurso | Notas |
|---|---|---|
| CPH | 8.2 - Nearest Smaller Element | |
| CSA | Stack Application - Soldier's Row | aplicación similar con animación |
Para resolver esto, guardamos una pila de pares e iteramos el arreglo de izquierda a derecha. Para algún índice , calculamos , el índice más a la derecha para , así:
- Seguir sacando el elemento del tope de la pila mientras . Esto es porque sabemos que el par que contiene nunca será la solución para ningún índice , ya que es menor o igual que y tiene un índice más a la derecha.
- Si , fijar en , porque una pila guarda primero los valores agregados más recientemente (o en este caso, los más a la derecha), de modo que contendrá el valor más a la derecha que es menor que . Luego, agregar a la pila.
La pila que usamos se llama pila monótona (monotonic stack) porque seguimos sacando el elemento del tope de la pila, lo que mantiene su monotonía (la misma propiedad que se necesita para algoritmos como la búsqueda binaria) porque los elementos de la pila son crecientes.
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
int N;
int main() {
ios_base::sync_with_stdio(0);
cin.tie(0);
cin >> N;
stack<pair<int, int>> stack;
stack.push({0, 0});
for (int i = 1; i <= N; ++i) {
int a;
cin >> a;
while (!stack.empty() && stack.top().first >= a) stack.pop();
cout << stack.top().second << " ";
stack.push({a, i});
}
}
/**
* author: Kai Wang
*/
import java.io.*;
import java.util.*;
public class NearestSmallestVals {
/**
* Mantenemos una pila de pares (ind, value)
* Recorremos el arreglo de izquierda a derecha y usamos ans para guardar
* respuestas
* Si el valor de a_i > (stk.peek()=a_k) entonces saco el tope de la
* pila. Esto está bien porque para todo j>k, a_j>=a_k, o (j,a_j) está en
* la pila. Si a_k < a_i entonces fijamos ans[i]=k e insertamos (i,a_i)
* Nótese que los elementos de la pila están ordenados por índice
*
*/
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int[] a = new int[N + 1];
StringTokenizer st = new StringTokenizer(br.readLine());
for (int i = 1; i <= N; i++) { a[i] = Integer.parseInt(st.nextToken()); }
Stack<Integer> stk = new Stack<>();
stk.add(0);
stk.add(1);
int[] ans = new int[N + 1];
ans[1] = 0;
for (int i = 2; i <= N; i++) {
while (a[stk.peek()] >= a[i]) { stk.pop(); }
// stk.peek()<a[i]
// Esto existe porque a[0]=0 y a[i]>0 para todo i>0
ans[i] = stk.peek();
stk.push(i);
}
for (int i = 1; i <= N; i++) { System.out.print(ans[i] + " "); }
}
}n = int(input())
nums = list(map(int, input().split()))
ans = []
stack = [] # guarda (a_i, i)
for idx, num in enumerate(nums):
while stack and stack[-1][0] >= num:
stack.pop()
ans.append(0 if not stack else stack[-1][1] + 1)
stack.append((num, idx))
print(*ans)Problemas
| Hecho | Fuente | Nombre | Dificultad | Tags | Solución |
|---|---|---|---|---|---|
| CSES | Advertisement | Fácil | Stack | Solución | |
| CF | ★ Mike and Feet | Normal | Stack | Solución | |
| CEOI | 2011 - Balloons | Normal | Stack, Geometry | Solución | |
| Baltic OI | 2012 - Mobile | Normal | Binary Search, Stack | Solución | |
| Gold | Modern Art 2 | Normal | Stack | Solución | |
| Gold | Dishwashing | Normal | Stack, Binary Search | Solución | |
| CSES | Maximum Building I | Normal | Stack | Solución | |
| CEOI | 2020 - Fancy Fence | Normal | Stack | — | |
| CF | Rectangles | Normal | Stack | Solución | |
| Gold | HILO | Difícil | Stack, Sorted Set, Linked List | Solución | |
| CSES | Increasing Array Queries | Difícil | Stack, PURS | Solución | |
| CF | ★ Skyline Photo | Difícil | Stack, PURS, DP | — | |
| IOI | 2004 - Empodia | Muy difícil | Stack | Solución | |
| Kilonova | ssdj | Muy difícil | Stack | Solución | |
| CSES | Maximum Building II | Insano | Stack | Solución | |
| COI | 2015 - Žarulje | Insano | Stack | Solución |