Encuentra la
hora punta de
cualquier sala

Mira cómo funciona

Un algoritmo de barrido que encuentra el momento de máximo aforo entre 300.000 reservas en unos 150 ms. El mismo código se ejecuta en tu navegador, en el servidor y en los tests.

En vivo · semana de gimnasio simulada · 50.000 reservas
HORA PUNTA DETECTADACalculando…
AFORO MÁXIMO–

01 · El algoritmo, paso a paso

Dos eventos por reserva, una sola pasada

Cada reserva se convierte en +1 al empezar y −1 al terminar. Los eventos se ordenan por tiempo, con los fines antes que los inicios, y todos los de un mismo instante se aplican antes de medir el aforo.

02 · Decisiones

Lo que el enunciado no decía

Las reglas que fijé ante lo ambiguo y cómo trato los casos límite. El resultado de cada ejemplo lo calcula en vivo la misma función maxOccupancy() que pasa los tests.

Regla

Intervalos semiabiertos [inicio, fin)

Quien sale a las 10 no coincide con quien entra a las 10: el fin no cuenta.

[[9, 10], [10, 11], [11, 12]]
Regla

Fines antes que inicios

En un mismo instante proceso primero las salidas y aplico todo el grupo antes de medir. Nunca cuento a alguien que ya se ha ido.

[[1, 5], [2, 5], [5, 9], [5, 9], [5, 9]]
Regla

El pico acaba en el siguiente evento

No fusiono tramos contiguos con el mismo aforo: el pico termina en cuanto entra o sale alguien.

[[1, 4], [2, 6], [4, 9]]
Regla

Empate: gana el que empieza antes

Recorro el tiempo hacia delante y solo actualizo con un «>» estricto, así que el primer pico se queda.

[[5, 7], [1, 3], [6, 8], [2, 4]]
Regla

Sin reservas y sin efectos secundarios

Sin reservas devuelvo [0, null, null]. Ordeno una lista nueva de eventos: el array de entrada nunca se modifica.

[]
Caso límite

Reserva de duración cero: se ignora

[5, 5) está vacía: nadie ocupa la sala. Si generara eventos, recortaría el pico de otras reservas.

[[3, 10], [5, 5]]
Caso límite

Inicio mayor que fin: error

Es un dato corrupto y darle la vuelta sería adivinar. Prefiero fallar pronto con RangeError (400 en la API) e indicar qué reserva está mal.

[[1, 2], [8, 3]]
Caso límite

Datos mal formados: error

Texto, NaN, Infinity o pares incompletos lanzan TypeError. Con NaN la ordenación fallaría en silencio.

[[1, "2"]]
Caso límite

Duplicados: cuentan por separado

Dos reservas idénticas son dos personas que reservaron el mismo hueco.

[[1, 5], [1, 5]]
Caso límite

Negativos y valores enormes: se aceptan

Solo importa el orden. Los números son exactos hasta 2⁵³; un timestamp en milisegundos ronda 1,7·10¹².

[[-10, -2], [-5, 3]]

03 · En el servidor

Hasta 1.000.000 de reservas por una API real

Un servidor node:http llama a maxOccupancy. El generador simula una semana de gimnasio: horas punta hacia las 8:00 y las 19:00, con los tiempos en minutos desde el lunes a las 00:00. Todo el trabajo pesado va en un Web Worker, así que la página nunca se congela.

Aforo máximo–
Pico–
Cálculo en servidor–
Ida y vuelta–
Datos enviados–

04 · Rendimiento

O(n²) contra O(n log n)

Las dos versiones se ejecutan en tu navegador con los mismos datos. La de fuerza bruta se detiene en 16.000 reservas; a partir de ahí se extrapola, porque tardaría minutos.

ReservasBarridoIngenua×
Pulsa «Empezar la carrera»

05 · API

Un endpoint, estricto con la entrada

POST /api/max-occupancy con un array JSON de reservas, o { "bookings": [...] }.

Petición

Respuesta

{
  "result": [3, 11, 12],
  "maxOccupancy": 3,
  "peakStart": 11,
  "peakEnd": 12,
  "bookings": 3,
  "elapsedMs": 0.021
}

Códigos de respuesta

  • 200Calculado
  • 400JSON inválido, reserva mal formada (TypeError) o inicio > fin (RangeError)
  • 405Cualquier método que no sea POST
  • 413Más de 32 MB o más de 1.000.000 de reservas
  • 429Más de 30 peticiones por minuto desde un mismo cliente

Por dentro

  • Node.js con node:http: sin frameworks ni dependencias
  • Archivos estáticos desde una lista cerrada y Content Security Policy estricta
  • Docker con sistema de archivos de solo lectura, detrás de Nginx con HTTPS