К обычному разбору
Тренировка по собеседованию2 задачиТехническое собеседованиеДата не указана

Technical screen: SQL и F-score

Идите сверху вниз: сначала попробуйте сами, затем откройте разбор. Если шаг с кодом, пишите решение прямо здесь и запускайте проверки на странице.

1SQL-задачаMedium

Модель последнего устройства пользователя

Условие

Есть пользователи, справочник устройств и история устройств пользователя.

Для каждого пользователя, у которого есть хотя бы одна запись в истории, нужно вернуть модель его последнего устройства.

Последнее устройство определяется так:

  • активная запись с end_date IS NULL считается новее закрытых записей;
  • иначе берем максимальный end_date;
  • при равном end_date берем максимальный start_date;
  • при полном tie берем больший device_id.

Верните:

  • user_id;
  • vendor_name;
  • model_name.

Сортировка: user_id ASC.

Schema

CREATE TABLE users (
  user_id INTEGER PRIMARY KEY,
  name TEXT NOT NULL
);

CREATE TABLE devices (
  device_id INTEGER PRIMARY KEY,
  vendor_name TEXT NOT NULL,
  model_name TEXT NOT NULL
);

CREATE TABLE device_history (
  user_id INTEGER NOT NULL,
  device_id INTEGER NOT NULL,
  start_date TEXT NOT NULL,
  end_date TEXT
);

Решение прямо на странице

Напишите код, запустите проверки и только потом открывайте разбор.

Проверка решения

Нажмите «Запустить проверки» или Ctrl+Enter.

Показать разбор

Идея решения

Нужно ранжировать строки истории внутри каждого пользователя. ROW_NUMBER() удобнее, чем GROUP BY MAX(end_date), потому что после выбора даты нужно вернуть связанные поля устройства и корректно обработать tie-break.

COALESCE(end_date, '9999-12-31') поднимает активное устройство наверх.

Эталонный код

WITH ranked_history AS (
  SELECT
    h.user_id,
    d.vendor_name,
    d.model_name,
    ROW_NUMBER() OVER (
      PARTITION BY h.user_id
      ORDER BY
        COALESCE(h.end_date, '9999-12-31') DESC,
        h.start_date DESC,
        h.device_id DESC
    ) AS rn
  FROM device_history h
  JOIN devices d ON d.device_id = h.device_id
)
SELECT user_id, vendor_name, model_name
FROM ranked_history
WHERE rn = 1
ORDER BY user_id;
Сложность
Время: O(n log n). Память: O(n).
ROW_NUMBER сортирует историю устройств внутри каждого user_id; join со справочником устройств линейный относительно размера результата.
2ЗадачаEasy

F-score по y_true и y_pred

Условие

Даны два массива одинаковой длины:

  • y_true — истинные бинарные метки 0/1;
  • y_pred — предсказанные бинарные метки 0/1.

Нужно посчитать F1-score для positive class 1.

Если precision и recall одновременно равны нулю, верните 0.0.

Сигнатура

def binary_f_score(y_true: list[int], y_pred: list[int]) -> float:

Решение прямо на странице

Напишите код, запустите проверки и только потом открывайте разбор.

Проверка решения

Нажмите «Запустить проверки» или Ctrl+Enter.

Показать разбор

Подсказки

  • Positive class

    Считайте TP, FP и FN только относительно класса 1.

  • Нулевой знаменатель

    Если модель не предсказала ни одного positive и в y_true нет positive, F-score должен быть 0.

Идея решения

Сначала считаем tp, fp и fn для positive class 1.

precision = tp / (tp + fp), recall = tp / (tp + fn), а затем F1 = 2 * precision * recall / (precision + recall). Если знаменатель F1 равен нулю, возвращаем 0.

Эталонный код

def binary_f_score(y_true: list[int], y_pred: list[int]) -> float:
    if len(y_true) != len(y_pred):
        raise ValueError('y_true and y_pred must have the same length')

    tp = fp = fn = 0
    for true_label, predicted_label in zip(y_true, y_pred):
        if true_label not in (0, 1) or predicted_label not in (0, 1):
            raise ValueError('labels must be 0 or 1')
        if predicted_label == 1 and true_label == 1:
            tp += 1
        elif predicted_label == 1 and true_label == 0:
            fp += 1
        elif predicted_label == 0 and true_label == 1:
            fn += 1

    precision = 0.0 if tp + fp == 0 else tp / (tp + fp)
    recall = 0.0 if tp + fn == 0 else tp / (tp + fn)
    if precision + recall == 0:
        return 0.0
    return 2 * precision * recall / (precision + recall)
Сложность
Время: O(n). Память: O(1).
Один проход по двум массивам для подсчета TP, FP и FN.