9.3 KiB
📝 Задача: Система управления событиями
Условие:
Вы разрабатываете систему для управления событиями (конференции, вебинары, встречи). Нужно реализовать сервис регистрации участников с учетом следующих требований:
-
Событие имеет:
- ID, название, описание
- Дату начала и окончания
- Максимальное количество участников
- Статус (DRAFT, PUBLISHED, CANCELLED)
-
Участник имеет:
- ID, имя, email
- Дату регистрации
-
Бизнес-правила:
- Регистрация возможна только на опубликованные события
- Нельзя зарегистрироваться на событие, которое уже началось
- Нельзя превысить лимит участников
- Один участник может зарегистрироваться на событие только один раз
- При отмене события нужно уведомить всех участников
Техническое задание:
Опишите подход к решению задачи:
- Архитектуру приложения - какие слои нужны
- Entity классы - основные поля и связи
- Ключевые методы EventRegistrationService
- Обработку бизнес-правил - где и как валидировать
- REST API endpoints - какие нужны
- Обработку ошибок - типы исключений
- Транзакции - где нужны и почему
- Тестирование - что важно покрыть тестами
Время на выполнение: 25 минут
🧮 Алгоритмическая задача для Middle разработчика
📝 Задача: Планировщик встреч
Условие:
У вас есть список встреч, каждая встреча представлена как массив [start, end], где start и end - время начала и окончания в минутах от начала дня.
Нужно найти максимальное количество непересекающихся встреч, которые можно провести в одной переговорной комнате.
Примеры:
Пример 1:
Ввод: meetings = [[0,30],[5,10],[15,20]]
Вывод: 2
Объяснение: Можно выбрать встречи [5,10] и [15,20]
Пример 2:
Ввод: meetings = [[7,10],[2,4]]
Вывод: 2
Объяснение: Обе встречи не пересекаются
Пример 3:
Ввод: meetings = [[1,5],[8,9],[8,9],[5,9],[9,15]]
Вывод: 3
Объяснение: Можно выбрать [1,5], [8,9], [9,15]
Ограничения:
1 <= meetings.length <= 10^4meetings[i].length == 20 <= starti < endi <= 10^6
Задание:
- Реализуйте метод
public int maxMeetings(int[][] meetings) - Объясните алгоритм и его сложность
- Напишите unit-тесты
Время на выполнение: 15 минут
✅ Решение алгоритмической задачи
Показать решение
Основная идея:
Это классическая задача о максимальном количестве непересекающихся интервалов. Используем жадный алгоритм:
- Сортируем встречи по времени окончания
- Выбираем встречу с самым ранним окончанием
- Исключаем все пересекающиеся с ней встречи
- Повторяем для оставшихся встреч
Решение:
import java.util.*;
public class MeetingScheduler {
public int maxMeetings(int[][] meetings) {
if (meetings == null || meetings.length == 0) {
return 0;
}
// Сортируем по времени окончания
Arrays.sort(meetings, (a, b) -> Integer.compare(a[1], b[1]));
int count = 0;
int lastEndTime = -1;
for (int[] meeting : meetings) {
int startTime = meeting[0];
int endTime = meeting[1];
// Если текущая встреча не пересекается с предыдущей выбранной
if (startTime >= lastEndTime) {
count++;
lastEndTime = endTime;
}
}
return count;
}
}
Объяснение алгоритма:
-
Сортировка: Сортируем все встречи по времени окончания. Это ключевая идея - выбирая встречи с самым ранним окончанием, мы оставляем максимум времени для последующих встреч.
-
Жадный выбор: Проходим по отсортированным встречам и выбираем те, которые не пересекаются с уже выбранными.
-
Условие непересечения: Встреча не пересекается с предыдущей, если её время начала >= времени окончания предыдущей.
Временная сложность: O(n log n) - из-за сортировки
Пространственная сложность: O(1) - если не считать пространство для сортировки
Пошаговый пример:
Для meetings = [[0,30],[5,10],[15,20]]:
- После сортировки по времени окончания:
[[5,10], [15,20], [0,30]] - Выбираем
[5,10],lastEndTime = 10 - Проверяем
[15,20]:15 >= 10✓, выбираем,lastEndTime = 20 - Проверяем
[0,30]:0 < 20✗, пропускаем - Результат: 2 встречи
Для meetings = [[1,5],[8,9],[8,9],[5,9],[9,15]]:
- После сортировки по времени окончания:
[[1,5], [8,9], [8,9], [5,9], [9,15]] - Выбираем
[1,5],lastEndTime = 5 - Проверяем
[8,9]:8 >= 5✓, выбираем,lastEndTime = 9 - Проверяем
[8,9]:8 < 9✗, пропускаем - Проверяем
[5,9]:5 < 9✗, пропускаем - Проверяем
[9,15]:9 >= 9✓, выбираем - Результат: 3 встречи
Unit тесты:
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.*;
class MeetingSchedulerTest {
private final MeetingScheduler scheduler = new MeetingScheduler();
@Test
void testExample1() {
int[][] meetings = {{0,30},{5,10},{15,20}};
assertEquals(2, scheduler.maxMeetings(meetings));
}
@Test
void testExample2() {
int[][] meetings = {{7,10},{2,4}};
assertEquals(2, scheduler.maxMeetings(meetings));
}
@Test
void testExample3() {
int[][] meetings = {{1,5},{8,9},{8,9},{5,9},{9,15}};
assertEquals(3, scheduler.maxMeetings(meetings));
}
@Test
void testEmptyInput() {
int[][] meetings = {};
assertEquals(0, scheduler.maxMeetings(meetings));
}
@Test
void testNullInput() {
assertEquals(0, scheduler.maxMeetings(null));
}
@Test
void testSingleMeeting() {
int[][] meetings = {{1,3}};
assertEquals(1, scheduler.maxMeetings(meetings));
}
@Test
void testAllOverlapping() {
int[][] meetings = {{1,4},{2,5},{3,6}};
assertEquals(1, scheduler.maxMeetings(meetings));
}
@Test
void testNoOverlapping() {
int[][] meetings = {{1,2},{3,4},{5,6}};
assertEquals(3, scheduler.maxMeetings(meetings));
}
@Test
void testTouchingMeetings() {
int[][] meetings = {{1,3},{3,5},{5,7}};
assertEquals(3, scheduler.maxMeetings(meetings));
}
}
Почему жадный алгоритм работает:
Выбирая встречу с самым ранним окончанием, мы всегда оставляем максимально возможное время для размещения остальных встреч. Это оптимальная стратегия для данной задачи.
Доказательство корректности: Пусть OPT - оптимальное решение, а GREEDY - решение жадного алгоритма. Можно показать, что GREEDY не хуже OPT путем замены встреч в OPT на встречи из GREEDY без ухудшения результата.