Как узнать
вход делится на половины, которые решаются сами по себе: отсортировать список, построить дерево по массиву или по двум обходам, дерево квадрантов, быстрое возведение в степень, слияние k отсортированных списков.
Как решать такие задачи
- Найди такое деление, после которого куски того же вида: две половины массива, список, разрезанный посередине, четыре квадранта.
- Запиши базу: самый маленький кусок, на который ответ известен сразу, — часто один элемент или пустой кусок.
- Реши каждый кусок рекурсивным вызовом и доверься, что вызов вернёт верный ответ.
- Напиши объединение и посчитай его стоимость на уровне: O(n) на уровень дают O(n log n) в сумме.
Вариант: Построить дерево
То же, но строим дерево: середина отсортированного массива становится корнем, а половины — его поддеревьями. Половины равны, плюс-минус один элемент, поэтому дерево получается сбалансированным.
- Передавай границы индексов (lo, hi), а не копии подмассивов: тогда деление стоит O(1).
- Пустой диапазон lo > hi — это база: он возвращает none.
- Выбери элемент, который делит остальное: середину отсортированного массива, первое значение прямого обхода для дерева по двум обходам.
- Создай узел, построй левую часть из одной половины и правую из другой, потом верни узел.
Где встречается
- Сортировка больших данных. Когда данные не помещаются в память, PostgreSQL сортирует их кусками, а потом сливает отсортированные куски. В EXPLAIN это видно как «external merge».
- Звук и сигналы. Быстрое преобразование Фурье делит сигнал на чётные и нечётные отсчёты, считает каждую половину тем же способом и склеивает результат. Так работают FFTW и numpy.fft.
- Умножение больших чисел. Python умножает очень длинные целые методом Карацубы: делит каждое число на две половины и обходится тремя умножениями половин вместо четырёх.