Задачи на подстроки

Базовый Algorithms
≈ 2 мин чтения

Подстрока — это непрерывный диапазон

Подстрока состоит из символов, идущих подряд. Это главное свойство, которое определяет выбор алгоритма: её удобно описывать двумя границами left и right, а затем двигать их вместо перебора всех возможных пар границ.

Перед решением полезно определить форму ограничения. Если длина фрагмента фиксирована — подходит фиксированное окно. Если окно можно расширять до нарушения условия и затем сжимать слева — часто подходит переменное окно. Если решение зависит от последнего появления символа, удобно дополнительно хранить позиции в таблице или map.

Пример: самый длинный фрагмент без повторов

Пусть нужно найти длину самой длинной подстроки, в которой символы не повторяются. Будем хранить последнюю известную позицию каждого символа. Если текущий символ уже встречался внутри окна, левую границу можно сразу перенести за его прошлую позицию.

Map<Character, Integer> lastSeen = new HashMap<>();
int left = 0;
int best = 0;

for (int right = 0; right < text.length(); right++) {
    char c = text.charAt(right);

    if (lastSeen.containsKey(c)) {
        left = Math.max(left, lastSeen.get(c) + 1);
    }

    lastSeen.put(c, right);
    best = Math.max(best, right - left + 1);
}

Выражение с Math.max принципиально важно: левая граница не должна возвращаться назад из-за старого появления символа, которое уже осталось за текущим окном. Каждый right проходит строку один раз, а left только движется вперёд, поэтому при среднем O(1) доступе к HashMap решение работает за O(n).

Не создавай подстроку без необходимости

Во время поиска обычно достаточно хранить границы и длину лучшего диапазона. Если задача требует вернуть сам текст, можно запомнить bestStart и создать substring один раз после завершения алгоритма. Так код не создаёт промежуточные строки на каждой итерации.

Сначала проверь, что задача действительно о непрерывном фрагменте. Подстрока и подпоследовательность — разные вещи: в подпоследовательности символы могут быть разделены пропусками. Техники sliding window обычно опираются именно на непрерывность.