From f5df2726a7ae80d7051bb95e75ddb019be86a4a1 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Mon, 18 Aug 2025 12:48:52 +0400 Subject: [PATCH] vault backup: 2025-08-18 12:48:52 --- .../Задачи/🧮 Алгоритмическая задача для Middle разработчика.md | 141 +++++++++++++----- 1 file changed, 103 insertions(+), 38 deletions(-) diff --git a/💼 Работа/Собеседования/Лето 2025/Задачи/🧮 Алгоритмическая задача для Middle разработчика.md b/💼 Работа/Собеседования/Лето 2025/Задачи/🧮 Алгоритмическая задача для Middle разработчика.md index 30fdbe2..e7b99e9 100644 --- a/💼 Работа/Собеседования/Лето 2025/Задачи/🧮 Алгоритмическая задача для Middle разработчика.md +++ b/💼 Работа/Собеседования/Лето 2025/Задачи/🧮 Алгоритмическая задача для Middle разработчика.md @@ -232,51 +232,43 @@ public int minTrucksNeeded(int[] orders, int capacity) { --- -## 📊 Задача 4: Анализ пиковых нагрузок склада +# 📊 Задача 4: Анализ пиковых нагрузок склада -### **Условие:** +## Условие: -Склад ведет учет количества активных заказов в каждый момент времени. Заказ активен с момента поступления до момента отправки. Найдите максимальное количество одновременно активных заказов. +Склад ведет учет количества активных заказов в каждый момент времени. Заказ активен с момента поступления до момента отправки (включая момент поступления, но НЕ включая момент отправки). Найдите максимальное количество одновременно активных заказов. -### **Входные данные:** +## Входные данные: -- `intervals` - массив интервалов `[start, end]`, где каждый интервал представляет время жизни заказа +1. `intervals` - массив интервалов `[start, end]`, где каждый интервал представляет время жизни заказа -### **Тестовые примеры:** +## Тестовые примеры: -**Пример 1:** +### Пример 1: -``` -Вход: intervals = [[1,3],[2,6],[8,10],[15,18]] -Выход: 2 -Объяснение: В момент времени 2-3 активны заказы [1,3] и [2,6] -``` +**Вход:** `intervals = [[1,3],[2,6],[8,10],[15,18]]` +**Выход:** `2` +**Объяснение:** В момент времени 2 активны заказы [1,3] и [2,6] -**Пример 2:** +### Пример 2: -``` -Вход: intervals = [[1,4],[4,5]] -Выход: 1 -Объяснение: Заказы не пересекаются по времени -``` +**Вход:** `intervals = [[1,4],[4,5]]` +**Выход:** `1` +**Объяснение:** Заказы не пересекаются по времени (первый заканчивается в момент 4, второй начинается в момент 4) -**Пример 3:** +### Пример 3: -``` -Вход: intervals = [[1,5],[2,3],[4,6],[7,8]] -Выход: 3 -Объяснение: В момент времени 4 активны [1,5], [2,3], [4,6] -``` +**Вход:** `intervals = [[1,5],[2,3],[4,6],[7,8]]` +**Выход:** `2` +**Объяснение:** Максимальное пересечение в моменты времени 2 и 4, когда активны по 2 заказа -### **Расширенные тестовые данные:** +### Расширенные тестовые данные: -``` -Вход: intervals = [[1,10],[2,4],[3,6],[4,8],[5,7],[6,9],[7,12]] -Выход: 5 -Объяснение: Максимальное пересечение в районе времени 6-7 -``` +**Вход:** `intervals = [[1,10],[2,4],[3,6],[4,8],[5,7],[6,9],[7,12]]` +**Выход:** `4` +**Объяснение:** Максимальное пересечение в районе времени 5-6, когда активны заказы [1,10], [3,6], [4,8], [5,7] -### **Решение:** +## Решение: ```java import java.util.*; @@ -294,8 +286,8 @@ public int maxConcurrentOrders(int[][] intervals) { events.add(new int[]{interval[1], -1}); // end: -1 } - // Сортируем события по времени, при равном времени сначала -1 (окончание) - events.sort((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]); + // ИСПРАВЛЕНИЕ: При равном времени сначала обрабатываем начало заказа (+1), потом конец (-1) + events.sort((a, b) -> a[0] == b[0] ? b[1] - a[1] : a[0] - b[0]); int maxConcurrent = 0; int currentConcurrent = 0; @@ -309,14 +301,87 @@ public int maxConcurrentOrders(int[][] intervals) { } ``` -**Временная сложность:** O(n log n) - сортировка событий -**Пространственная сложность:** O(n) - список событий +### Альтернативное решение (JavaScript): -### **Дополнительные вопросы:** +```javascript +function maxConcurrentOrders(intervals) { + if (!intervals || intervals.length === 0) { + return 0; + } + + let events = []; + + // Создаем события начала и конца заказов + for (let interval of intervals) { + events.push([interval[0], 1]); // start: +1 + events.push([interval[1], -1]); // end: -1 + } + + // При равном времени сначала обрабатываем начало заказа (+1), потом конец (-1) + events.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]); + + let maxConcurrent = 0; + let currentConcurrent = 0; + + for (let event of events) { + currentConcurrent += event[1]; + maxConcurrent = Math.max(maxConcurrent, currentConcurrent); + } + + return maxConcurrent; +} +``` -1. Как найти конкретный момент времени, когда достигается максимум? -2. Как адаптировать алгоритм для поиска минимального количества рабочих станций? +## Ключевые исправления: +1. **Сортировка событий:** При одинаковом времени сначала обрабатываем события начала заказа (+1), затем события окончания (-1). Это важно, так как заказ считается активным в момент начала, но НЕ активным в момент окончания. + +2. **Объяснения к примерам:** Исправлены неточности в объяснениях результатов. + +3. **Расширенный пример:** Пересчитан правильный результат. + + +## Сложность: + +- **Временная сложность:** O(n log n) - сортировка событий +- **Пространственная сложность:** O(n) - список событий + +## Дополнительные вопросы: + +### 1. Как найти конкретный момент времени, когда достигается максимум? + +```java +public List findPeakTimes(int[][] intervals) { + // ... тот же код до цикла обработки событий + + List peakTimes = new ArrayList<>(); + int maxConcurrent = 0; + int currentConcurrent = 0; + + for (int[] event : events) { + currentConcurrent += event[1]; + if (currentConcurrent > maxConcurrent) { + maxConcurrent = currentConcurrent; + peakTimes.clear(); + peakTimes.add(event[0]); + } else if (currentConcurrent == maxConcurrent && event[1] == 1) { + peakTimes.add(event[0]); + } + } + + return peakTimes; +} +``` + +### 2. Как адаптировать алгоритм для поиска минимального количества рабочих станций? + +Алгоритм остается тем же - максимальное количество одновременно активных заказов и есть минимальное количество рабочих станций, необходимых для обработки всех заказов без задержек. + +## Важные моменты: + +- Заказ активен в интервале `[start, end)` - включая start, но исключая end +- При одновременном начале и окончании заказов сначала обрабатываем начало +- Алгоритм основан на технике "sweep line" (сканирующая прямая) --- ## 🔍 Задача 5: Поиск товаров в секционированном складе