From 6b59e2e33f71e920ad486f71450c46d1ed3c48aa Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Wed, 13 Aug 2025 14:53:57 +0400 Subject: [PATCH] vault backup: 2025-08-13 14:53:57 --- .../Задачи/💼 Прикладная задача для Middle разработчика.md | 207 ------------------ .../Задачи/🧮 Алгоритмическая задача для Middle разработчика.md | 204 +++++++++++++++++ 2 files changed, 204 insertions(+), 207 deletions(-) create mode 100644 💼 Работа/Собеседования/Лето 2025/Задачи/🧮 Алгоритмическая задача для Middle разработчика.md diff --git a/💼 Работа/Собеседования/Лето 2025/Задачи/💼 Прикладная задача для Middle разработчика.md b/💼 Работа/Собеседования/Лето 2025/Задачи/💼 Прикладная задача для Middle разработчика.md index e636226..f845d6c 100644 --- a/💼 Работа/Собеседования/Лето 2025/Задачи/💼 Прикладная задача для Middle разработчика.md +++ b/💼 Работа/Собеседования/Лето 2025/Задачи/💼 Прикладная задача для Middle разработчика.md @@ -36,210 +36,3 @@ 8. **Тестирование** - что важно покрыть тестами **Время на выполнение:** 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^4` -- `meetings[i].length == 2` -- `0 <= starti < endi <= 10^6` - -### **Задание:** - -1. Реализуйте метод `public int maxMeetings(int[][] meetings)` -2. Объясните алгоритм и его сложность -3. Напишите unit-тесты - -**Время на выполнение:** 15 минут - ---- - -# ✅ Решение алгоритмической задачи - -
Показать решение - -### **Основная идея:** - -Это классическая задача о максимальном количестве непересекающихся интервалов. Используем жадный алгоритм: - -1. Сортируем встречи по времени окончания -2. Выбираем встречу с самым ранним окончанием -3. Исключаем все пересекающиеся с ней встречи -4. Повторяем для оставшихся встреч - -### **Решение:** - -```java -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; - } -} -``` - -### **Объяснение алгоритма:** - -1. **Сортировка:** Сортируем все встречи по времени окончания. Это ключевая идея - выбирая встречи с самым ранним окончанием, мы оставляем максимум времени для последующих встреч. - -2. **Жадный выбор:** Проходим по отсортированным встречам и выбираем те, которые не пересекаются с уже выбранными. - -3. **Условие непересечения:** Встреча не пересекается с предыдущей, если её время начала >= времени окончания предыдущей. - - -### **Временная сложность:** O(n log n) - из-за сортировки - -### **Пространственная сложность:** O(1) - если не считать пространство для сортировки - -### **Пошаговый пример:** - -Для `meetings = [[0,30],[5,10],[15,20]]`: - -1. После сортировки по времени окончания: `[[5,10], [15,20], [0,30]]` -2. Выбираем `[5,10]`, `lastEndTime = 10` -3. Проверяем `[15,20]`: `15 >= 10` ✓, выбираем, `lastEndTime = 20` -4. Проверяем `[0,30]`: `0 < 20` ✗, пропускаем -5. Результат: 2 встречи - -Для `meetings = [[1,5],[8,9],[8,9],[5,9],[9,15]]`: - -1. После сортировки по времени окончания: `[[1,5], [8,9], [8,9], [5,9], [9,15]]` -2. Выбираем `[1,5]`, `lastEndTime = 5` -3. Проверяем `[8,9]`: `8 >= 5` ✓, выбираем, `lastEndTime = 9` -4. Проверяем `[8,9]`: `8 < 9` ✗, пропускаем -5. Проверяем `[5,9]`: `5 < 9` ✗, пропускаем -6. Проверяем `[9,15]`: `9 >= 9` ✓, выбираем -7. Результат: 3 встречи - -### **Unit тесты:** - -```java -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 без ухудшения результата. - -
\ No newline at end of file diff --git a/💼 Работа/Собеседования/Лето 2025/Задачи/🧮 Алгоритмическая задача для Middle разработчика.md b/💼 Работа/Собеседования/Лето 2025/Задачи/🧮 Алгоритмическая задача для Middle разработчика.md new file mode 100644 index 0000000..fb6893c --- /dev/null +++ b/💼 Работа/Собеседования/Лето 2025/Задачи/🧮 Алгоритмическая задача для Middle разработчика.md @@ -0,0 +1,204 @@ +# 🧮 Алгоритмическая задача для 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^4` +- `meetings[i].length == 2` +- `0 <= starti < endi <= 10^6` + +### **Задание:** + +1. Реализуйте метод `public int maxMeetings(int[][] meetings)` +2. Объясните алгоритм и его сложность +3. Напишите unit-тесты + +**Время на выполнение:** 15 минут + +--- + +# ✅ Решение алгоритмической задачи + +
Показать решение + +### **Основная идея:** + +Это классическая задача о максимальном количестве непересекающихся интервалов. Используем жадный алгоритм: + +1. Сортируем встречи по времени окончания +2. Выбираем встречу с самым ранним окончанием +3. Исключаем все пересекающиеся с ней встречи +4. Повторяем для оставшихся встреч + +### **Решение:** + +```java +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; + } +} +``` + +### **Объяснение алгоритма:** + +1. **Сортировка:** Сортируем все встречи по времени окончания. Это ключевая идея - выбирая встречи с самым ранним окончанием, мы оставляем максимум времени для последующих встреч. + +2. **Жадный выбор:** Проходим по отсортированным встречам и выбираем те, которые не пересекаются с уже выбранными. + +3. **Условие непересечения:** Встреча не пересекается с предыдущей, если её время начала >= времени окончания предыдущей. + + +### **Временная сложность:** O(n log n) - из-за сортировки + +### **Пространственная сложность:** O(1) - если не считать пространство для сортировки + +### **Пошаговый пример:** + +Для `meetings = [[0,30],[5,10],[15,20]]`: + +1. После сортировки по времени окончания: `[[5,10], [15,20], [0,30]]` +2. Выбираем `[5,10]`, `lastEndTime = 10` +3. Проверяем `[15,20]`: `15 >= 10` ✓, выбираем, `lastEndTime = 20` +4. Проверяем `[0,30]`: `0 < 20` ✗, пропускаем +5. Результат: 2 встречи + +Для `meetings = [[1,5],[8,9],[8,9],[5,9],[9,15]]`: + +1. После сортировки по времени окончания: `[[1,5], [8,9], [8,9], [5,9], [9,15]]` +2. Выбираем `[1,5]`, `lastEndTime = 5` +3. Проверяем `[8,9]`: `8 >= 5` ✓, выбираем, `lastEndTime = 9` +4. Проверяем `[8,9]`: `8 < 9` ✗, пропускаем +5. Проверяем `[5,9]`: `5 < 9` ✗, пропускаем +6. Проверяем `[9,15]`: `9 >= 9` ✓, выбираем +7. Результат: 3 встречи + +### **Unit тесты:** + +```java +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 без ухудшения результата. + +
\ No newline at end of file