Files
second-mind-aep/💼 Работа/Собеседования/Лето 2025/Задачи/🧮 Алгоритмическая задача для Middle разработчика.md
2025-08-13 17:50:19 +04:00

26 KiB
Raw Blame History

🏷️ Задача 1: Оптимальная маршрутизация сборщика заказов

Условие:

Сборщик заказов должен собрать товары с полок, расположенных в ряд. Каждая полка имеет координату (позицию) и может содержать один или несколько товаров. Сборщик стартует с позиции 0 и должен посетить все полки с товарами, минимизируя пройденное расстояние.

Найдите минимальное расстояние, которое нужно пройти сборщику.

Входные данные:

  • positions - массив позиций полок с товарами (отсортированный)

Тестовые примеры:

Пример 1:

Вход: positions = [2, 3, 10, 15]
Выход: 15
Объяснение: Идем от 0 до 15, проходим все полки: 0→2→3→10→15

Пример 2:

Вход: positions = [1, 9]
Выход: 9  
Объяснение: 0→1→9 или 0→9→1, оба пути дают расстояние 9

Пример 3:

Вход: positions = [5]
Выход: 5
Объяснение: Просто идем к позиции 5

Расширенные тестовые данные:

Вход: positions = [1, 2, 5, 8, 12, 16, 20, 25, 30, 35]
Выход: 35
Объяснение: Оптимальный путь 0→1→2→5→8→12→16→20→25→30→35

Решение:

public int minDistanceToCollectItems(int[] positions) {
    if (positions == null || positions.length == 0) {
        return 0;
    }
    
    // Поскольку нужно посетить все позиции и они отсортированы,
    // оптимально идти от начала до конца
    return positions[positions.length - 1];
}

Временная сложность: O(1)
Пространственная сложность: O(1)

Дополнительные вопросы:

  1. Как изменится решение, если сборщик может начать с любой позиции?
  2. Что если некоторые полки содержат приоритетные товары, которые нужно собрать в первую очередь?

📦 Задача 2: Укладка коробок разных размеров

Условие:

На складе нужно уложить коробки в стеллаж. Каждая коробка имеет высоту, и стеллаж имеет максимальную высоту H. Коробки можно ставить только одна на другую. Найдите максимальное количество коробок, которые можно уложить в стеллаж.

Входные данные:

  • heights - массив высот коробок
  • maxHeight - максимальная высота стеллажа

Тестовые примеры:

Пример 1:

Вход: heights = [1, 3, 2, 4], maxHeight = 6
Выход: 3
Объяснение: Можем взять коробки высотой [1, 2, 3] = 6

Пример 2:

Вход: heights = [2, 5, 1, 3], maxHeight = 7
Выход: 3  
Объяснение: [1, 2, 3] = 6 или [1, 3, 2] = 6, но не можем добавить коробку высотой 5

Пример 3:

Вход: heights = [5, 4, 6], maxHeight = 10
Выход: 2
Объяснение: Максимум можем взять [4, 5] = 9 или [4, 6] = 10

Расширенные тестовые данные:

Вход: heights = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5], maxHeight = 15
Выход: 6
Объяснение: [1, 1, 2, 2, 3, 3] = 12 или другие комбинации из 6 коробок

Решение:

import java.util.Arrays;

public int maxBoxes(int[] heights, int maxHeight) {
    if (heights == null || heights.length == 0) {
        return 0;
    }
    
    // Сортируем коробки по высоте (жадный подход)
    Arrays.sort(heights);
    
    int totalHeight = 0;
    int count = 0;
    
    for (int height : heights) {
        if (totalHeight + height <= maxHeight) {
            totalHeight += height;
            count++;
        } else {
            break;
        }
    }
    
    return count;
}

Временная сложность: O(n log n) - из-за сортировки
Пространственная сложность: O(1)

Дополнительные вопросы:

  1. Как изменится алгоритм, если коробки имеют еще и вес, и есть ограничение по весу?
  2. Что если коробки нельзя переворачивать и у них есть определенная ориентация?

🚛 Задача 3: Планирование загрузки грузовиков

Условие:

Склад должен отправить заказы разного веса на грузовиках. Каждый грузовик может везти максимум capacity единиц веса. Заказы должны быть отправлены в порядке поступления (нельзя менять порядок). Найдите минимальное количество грузовиков, необходимое для отправки всех заказов.

Входные данные:

  • orders - массив весов заказов
  • capacity - грузоподъемность одного грузовика

Тестовые примеры:

Пример 1:

Вход: orders = [1, 2, 3, 4, 5], capacity = 5
Выход: 4
Объяснение: [1,2] [3] [4] [5] - 4 грузовика

Пример 2:

Вход: orders = [3, 2, 2, 1], capacity = 6
Выход: 2
Объяснение: [3,2] [2,1] - 2 грузовика или [3] [2,2,1] - тоже 2

Пример 3:

Вход: orders = [1, 1, 1, 1, 1], capacity = 3
Выход: 2
Объяснение: [1,1,1] [1,1] - 2 грузовика

Расширенные тестовые данные:

Вход: orders = [2, 3, 1, 4, 2, 3, 1, 2], capacity = 8
Выход: 3
Объяснение: [2,3,1] [4,2] [3,1,2] - 3 грузовика

Решение:

public int minTrucksNeeded(int[] orders, int capacity) {
    if (orders == null || orders.length == 0) {
        return 0;
    }
    
    int trucks = 1;
    int currentLoad = 0;
    
    for (int order : orders) {
        if (currentLoad + order <= capacity) {
            currentLoad += order;
        } else {
            // Нужен новый грузовик
            trucks++;
            currentLoad = order;
        }
    }
    
    return trucks;
}

Временная сложность: O(n)
Пространственная сложность: O(1)

Дополнительные вопросы:

  1. Как решить задачу, если можно менять порядок заказов?
  2. Что если разные грузовики имеют разную грузоподъемность?

📊 Задача 4: Анализ пиковых нагрузок склада

Условие:

Склад ведет учет количества активных заказов в каждый момент времени. Заказ активен с момента поступления до момента отправки. Найдите максимальное количество одновременно активных заказов.

Входные данные:

  • intervals - массив интервалов [start, end], где каждый интервал представляет время жизни заказа

Тестовые примеры:

Пример 1:

Вход: intervals = [[1,3],[2,6],[8,10],[15,18]]
Выход: 2
Объяснение: В момент времени 2-3 активны заказы [1,3] и [2,6]

Пример 2:

Вход: intervals = [[1,4],[4,5]]
Выход: 1
Объяснение: Заказы не пересекаются по времени

Пример 3:

Вход: intervals = [[1,5],[2,3],[4,6],[7,8]]
Выход: 3
Объяснение: В момент времени 4 активны [1,5], [2,3], [4,6]

Расширенные тестовые данные:

Вход: intervals = [[1,10],[2,4],[3,6],[4,8],[5,7],[6,9],[7,12]]
Выход: 5
Объяснение: Максимальное пересечение в районе времени 6-7

Решение:

import java.util.*;

public int maxConcurrentOrders(int[][] intervals) {
    if (intervals == null || intervals.length == 0) {
        return 0;
    }
    
    List<int[]> events = new ArrayList<>();
    
    // Создаем события начала и конца заказов
    for (int[] interval : intervals) {
        events.add(new int[]{interval[0], 1});  // start: +1
        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]);
    
    int maxConcurrent = 0;
    int currentConcurrent = 0;
    
    for (int[] event : events) {
        currentConcurrent += event[1];
        maxConcurrent = Math.max(maxConcurrent, currentConcurrent);
    }
    
    return maxConcurrent;
}

Временная сложность: O(n log n) - сортировка событий
Пространственная сложность: O(n) - список событий

Дополнительные вопросы:

  1. Как найти конкретный момент времени, когда достигается максимум?
  2. Как адаптировать алгоритм для поиска минимального количества рабочих станций?

🔍 Задача 5: Поиск товаров в секционированном складе

Условие:

Склад разделен на секции, в каждой секции товары отсортированы по ID. Некоторые секции могут быть пустыми. Нужно найти секцию, содержащую товар с заданным ID.

Входные данные:

  • sections - двумерный массив, где каждая строка представляет секцию с отсортированными ID товаров
  • target - искомый ID товара

Тестовые примеры:

Пример 1:

Вход: sections = [[1,4,7,11],[],[2,5,9,10,13],[3,6,8,16]], target = 5
Выход: 2
Объяснение: Товар с ID 5 находится в секции 2 (индексация с 0)

Пример 2:

Вход: sections = [[1,3,5],[2,4,6]], target = 7
Выход: -1
Объяснение: Товар с ID 7 не найден

Пример 3:

Вход: sections = [[],[1,2,3],[4,5,6]], target = 1
Выход: 1
Объяснение: Товар с ID 1 находится в секции 1

Расширенные тестовые данные:

Вход: sections = [[1,5,9,13],[2,6,10,14],[3,7,11,15],[4,8,12,16]], target = 11
Выход: 2
Объяснение: Товар с ID 11 находится в секции 2

Решение:

public int searchInSections(int[][] sections, int target) {
    if (sections == null || sections.length == 0) {
        return -1;
    }
    
    for (int i = 0; i < sections.length; i++) {
        if (sections[i].length == 0) {
            continue;
        }
        
        // Проверяем, может ли target быть в этой секции
        if (target >= sections[i][0] && target <= sections[i][sections[i].length - 1]) {
            // Выполняем бинарный поиск в секции
            if (binarySearch(sections[i], target)) {
                return i;
            }
        }
    }
    
    return -1;
}

private boolean binarySearch(int[] array, int target) {
    int left = 0, right = array.length - 1;
    
    while (left <= right) {
        int mid = left + (right - left) / 2;
        
        if (array[mid] == target) {
            return true;
        } else if (array[mid] < target) {
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }
    
    return false;
}

Временная сложность: O(m + log n), где m - количество секций, n - максимальный размер секции
Пространственная сложность: O(1)

Дополнительные вопросы:

  1. Как изменить алгоритм, чтобы найти все секции, содержащие товар?
  2. Что если секции не отсортированы и нужно оптимизировать поиск?

🏃‍♂️ Задача 6: Оптимизация маршрута между зонами склада

Условие:

Склад имеет зоны, соединенные коридорами. Сотрудник должен пройти через определенные зоны в заданном порядке. Каждый переход между соседними зонами занимает 1 единицу времени. Зоны пронумерованы последовательно. Найдите минимальное время для прохождения всех зон в порядке.

Входные данные:

  • zones - массив номеров зон в порядке посещения

Тестовые примеры:

Пример 1:

Вход: zones = [1, 3, 6, 7]
Выход: 6
Объяснение: 1→3 (2 шага) + 3→6 (3 шага) + 6→7 (1 шаг) = 6

Пример 2:

Вход: zones = [2, 2, 2]
Выход: 0
Объяснение: Остаемся в той же зоне, время = 0

Пример 3:

Вход: zones = [10, 5, 8]
Выход: 8
Объяснение: 10→5 (5 шагов) + 5→8 (3 шага) = 8

Расширенные тестовые данные:

Вход: zones = [1, 10, 3, 8, 2, 15, 7]
Выход: 35
Объяснение: |1-10| + |10-3| + |3-8| + |8-2| + |2-15| + |15-7| = 9+7+5+6+13+8 = 48

Решение:

public int minTimeToVisitZones(int[] zones) {
    if (zones == null || zones.length <= 1) {
        return 0;
    }
    
    int totalTime = 0;
    
    for (int i = 1; i < zones.length; i++) {
        totalTime += Math.abs(zones[i] - zones[i - 1]);
    }
    
    return totalTime;
}

Временная сложность: O(n)
Пространственная сложность: O(1)

Дополнительные вопросы:

  1. Как решить задачу, если можно изменить порядок посещения зон?
  2. Что если некоторые переходы между зонами заблокированы?

📋 Задача 7: Группировка заказов по приоритету

Условие:

На складе есть заказы с разными приоритетами (числа от 1 до k). Заказы одного приоритета должны обрабатываться вместе. Найдите количество групп заказов одинакового приоритета, стоящих подряд.

Входные данные:

  • priorities - массив приоритетов заказов

Тестовые примеры:

Пример 1:

Вход: priorities = [1, 1, 2, 2, 3, 1, 1]
Выход: 4
Объяснение: Группы: [1,1], [2,2], [3], [1,1]

Пример 2:

Вход: priorities = [1, 2, 1, 2]
Выход: 4
Объяснение: Группы: [1], [2], [1], [2]

Пример 3:

Вход: priorities = [3, 3, 3, 3]
Выход: 1
Объяснение: Одна группа: [3,3,3,3]

Расширенные тестовые данные:

Вход: priorities = [1, 1, 2, 3, 3, 3, 2, 2, 1, 1, 1, 4, 4]
Выход: 6
Объяснение: [1,1], [2], [3,3,3], [2,2], [1,1,1], [4,4]

Решение:

public int countPriorityGroups(int[] priorities) {
    if (priorities == null || priorities.length == 0) {
        return 0;
    }
    
    int groups = 1;
    
    for (int i = 1; i < priorities.length; i++) {
        if (priorities[i] != priorities[i - 1]) {
            groups++;
        }
    }
    
    return groups;
}

Временная сложность: O(n)
Пространственная сложность: O(1)

Дополнительные вопросы:

  1. Как найти самую длинную группу заказов одного приоритета?
  2. Что если нужно найти количество различных приоритетов в массиве?

🎯 Задача 8: Поиск оптимального места хранения

Условие:

На складе есть ряд мест хранения, некоторые заняты (1), некоторые свободны (0). Нужно найти самую длинную последовательность свободных мест для размещения крупногабаритного товара.

Входные данные:

  • storage - массив состояний мест хранения (0 - свободно, 1 - занято)

Тестовые примеры:

Пример 1:

Вход: storage = [1, 0, 0, 0, 1, 0, 0]
Выход: 3
Объяснение: Последовательность [0,0,0] имеет длину 3

Пример 2:

Вход: storage = [0, 0, 1, 0, 0, 0, 0, 1]
Выход: 4
Объяснение: Последовательность [0,0,0,0] имеет длину 4

Пример 3:

Вход: storage = [1, 1, 1, 1]
Выход: 0
Объяснение: Нет свободных мест

Расширенные тестовые данные:

Вход: storage = [0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0]
Выход: 5
Объяснение: Последовательность [0,0,0,0,0] имеет максимальную длину 5

Решение:

public int longestFreeSpace(int[] storage) {
    if (storage == null || storage.length == 0) {
        return 0;
    }
    
    int maxLength = 0;
    int currentLength = 0;
    
    for (int space : storage) {
        if (space == 0) {
            currentLength++;
            maxLength = Math.max(maxLength, currentLength);
        } else {
            currentLength = 0;
        }
    }
    
    return maxLength;
}

Временная сложность: O(n)
Пространственная сложность: O(1)

Дополнительные вопросы:

  1. Как найти позицию начала самой длинной последовательности?
  2. Что если можно освободить k занятых мест для увеличения свободного пространства?

🔄 Задача 9: Ротация стеллажей для доступа к товарам

Условие:

Автоматический стеллаж представляет собой кольцевую структуру с ячейками. Чтобы получить доступ к товару в определенной ячейке, стеллаж можно поворачивать влево или вправо. Каждый поворот на одну позицию занимает 1 единицу времени. Найдите минимальное время для доступа ко всем товарам в заданном порядке.

Входные данные:

  • n - количество ячеек в стеллаже (нумерация 0 до n-1)
  • targets - порядок ячеек для доступа к товарам
  • start - начальная позиция

Тестовые примеры:

Пример 1:

Вход: n = 4, targets = [0, 1, 3], start = 0
Выход: 3
Объяснение: 0→1 (1 шаг) + 1→3 (2 шага) = 3

Пример 2:

Вход: n = 5, targets = [4, 0, 2], start = 1
Выход: 4
Объяснение: 1→4 (2 шага) + 4→0 (1 шаг) + 0→2 (2 шага) = 5
Проверим: 1→4 влево (3 шага) или вправо (2 шага) - выбираем 2
4→0 влево (1 шаг) или вправо (4 шага) - выбираем 1
0→2 (2 шага в любую сторону) = 2+1+2 = 5

Пример 3:

Вход: n = 3, targets = [2], start = 1
Выход: 1
Объяснение: 1→2 (1 шаг в любую сторону)

Расширенные тестовые данные:

Вход: n = 8, targets = [7, 1, 3, 5], start = 0
Выход: 8

Решение:

public int minTimeToAccessItems(int n, int[] targets, int start) {
    if (targets == null || targets.length == 0) {
        return 0;
    }
    
    int totalTime = 0;
    int currentPos = start;
    
    for (int target : targets) {
        int clockwise = (target - currentPos + n) % n;
        int counterclockwise = (currentPos - target + n) % n;
        
        totalTime += Math.min(clockwise, counterclockwise);
        currentPos = target;
    }
    
    return totalTime;
}

Временная сложность: O(m), где m - количество целевых позиций
Пространственная сложность: O(1)

Дополнительные вопросы:

  1. Как изменится решение, если можно изменить порядок доступа к товарам?
  2. Что если стеллаж может вращаться с разной скоростью в разных направлениях?

📈 Задача 10: Анализ производительности конвейера

Условие:

На конвейере обрабатываются товары. В каждый момент времени известна скорость конвейера. Найдите период времени, когда средняя скорость была максимальной для окна размером k.

Входные данные:

  • speeds - массив скоростей конвейера в разные моменты времени
  • k - размер временного окна

Тестовые примеры:

Пример 1:

Вход: speeds = [1, 3, 2, 6, 4], k = 3
Выход: 2
Объяснение: Окна: [1,3,2]=6, [3,2,6]=11, [2,6,4]=12. Максимум в позиции 2

Пример 2:

Вход: speeds = [5, 2, 1, 8, 9], k = 2
Выход: 3
Объяснение: Окна: [5,2]=7, [2,1]=3, [1,8]=9, [8,9]=17. Максимум в позиции 3

Пример 3:

Вход: speeds = [1, 2, 3, 4, 5], k = 1
Выход: 4
Объяснение: Максимальная скорость 5 в позиции 4

Расширенные тестовые данные:

Вход: speeds = [2, 1, 3, 4, 6, 7, 8, 1, 2], k = 4
Выход: 4
Объяснение: Нужно найти окно размером 4 с максимальной суммой

Решение:

public int maxAverageWindow(int[] speeds, int k) {
    if (speeds == null || speeds.length < k) {
        return -1;
    }
    
    // Вычисляем сумму первого окна
    int windowSum = 0;
    for (int i = 0; i < k; i++) {
        windowSum += speeds[i];
    }
    
    int maxSum = windowSum;
    int maxIndex = 0;
    
    // Скользящее окно
    for (int i = k; i < speeds.length; i++) {
        windowSum = windowSum - speeds[i - k] + speeds[i];
        
        if (windowSum > maxSum) {
            maxSum = windowSum;
            maxIndex = i - k + 1;
        }
    }
    
    return maxIndex;
}

Временная сложность: O(n)
Пространственная сложность: O(1)

Дополнительные вопросы:

  1. Как найти все окна с максимальной средней скоростью?
  2. Что если нужно найти окно с минимальной дисперсией скоростей?

📝 Инструкции по использованию

Для интервьюера:

  1. Выбор задач: Для Middle разработчика рекомендуется 2-3 задачи на 30-45 минут

  2. Оценка: Обращайте внимание на:

    • Правильность алгоритма
    • Оптимальность решения
    • Качество кода
    • Обработку граничных случаев
    • Ответы на дополнительные вопросы
  3. Подсказки: Если кандидат затрудняется, можно дать наводящие вопросы по теме складской логистики

Уровни сложности:

  • Easy: Задачи 1