Собесов

Glassdoor (Amazon) — час, в котором было больше всего одновременных юзеров

SQLInterval overlapСложнаяSenior

Условие

Таблица sessions(user_id, login_time, logout_time) — сессии онлайна. Найдите час суток, в который было максимальное число одновременно онлайн-пользователей.

Решение

Подход 1 — sweep line по событиям

Идея: каждый login = +1, каждый logout = -1. Сортируем по времени и считаем накопительную сумму.

WITH events AS (
  SELECT login_time AS ts, 1 AS delta FROM sessions
  UNION ALL
  SELECT logout_time AS ts, -1 AS delta FROM sessions
),
running AS (
  SELECT ts, SUM(delta) OVER (ORDER BY ts, delta DESC) AS online_count
  FROM events
)
SELECT EXTRACT(HOUR FROM ts) AS hour, MAX(online_count) AS peak
FROM running
GROUP BY EXTRACT(HOUR FROM ts)
ORDER BY peak DESC
LIMIT 1;

Деталь: ORDER BY ts, delta DESC — на одно и то же время сначала обрабатываем login (+1), потом logout (-1). Это договорённость; при ts_login = ts_logout чёткой картины «одновременности» нет.

Подход 2 — calendar table часов и CROSS JOIN

WITH hours AS (
  SELECT generate_series(0, 23) AS h
)
SELECT h.h AS hour, COUNT(*) AS online_in_hour
FROM hours h
JOIN sessions s
  ON EXTRACT(HOUR FROM s.login_time) <= h.h
 AND EXTRACT(HOUR FROM s.logout_time) >= h.h
GROUP BY h.h
ORDER BY online_in_hour DESC
LIMIT 1;

Этот вариант наивен: считает «сессию, частично попавшую в час», а не «одновременно онлайн в любой момент часа». Для интервью обычно ждут sweep-line.

Подводные камни

  1. UNION без ALL. Удалит «равные» события (две логина в одно мгновение) — задвоится подсчёт. Только UNION ALL.
  2. Logout = NULL. Если пользователь ещё онлайн — logout_time IS NULL. Заменить на CURRENT_TIMESTAMP. Иначе строка просто пропадёт из UNION.
  3. EXTRACT(HOUR ...) теряет дату. Если просят «час за все дни» — норм. Если просят «час конкретного дня» — нужно DATE_TRUNC('hour', ...).
  4. Тай-брейк часов. Если у двух часов одинаковый пик — LIMIT 1 даст случайный. RANK() = 1 или возврат всех.

Эталонный ответ

Sweep-line через UNION ALL login/logout с весами +1/-1, SUM OVER (ORDER BY ts) для running count, MAX по часу. Очень популярный паттерн на собесах в FAANG.

Хочешь увидеть разбор?

Зарегистрируйся бесплатно — откроется развёрнутое решение этой задачи и ещё 4 на выбор.

Зарегистрироваться и увидеть разбор
Уже есть аккаунт? Войти