РУҚА
Тапсырмалар № 25, 26, 27 · ЕГЭ

Сортировка и два указателя

Как после сортировки находить пары, диапазоны и непрерывные группы за линейное время
6 мин чтенияҚиындық: Обновлено 29 қыркүйек 2026

Предварительная сортировка превращает неупорядоченный массив в последовательность, где легко сравнивать соседние элементы и отбрасывать целые группы неподходящих значений. В этой теме разберём, как сочетать сортировку массива и метод двух указателей при поиске пар, диапазонов и серий.

Зачем сортировать массив

Пусть дан массив чисел и требуется найти два элемента с заданным свойством: сумма равна \(S\), разность не превышает \(D\), произведение меньше порога или оба элемента лежат в одном диапазоне. Если проверять все пары, получится \(O(n^2)\) сравнений. После сортировки элементы расположены по возрастанию, поэтому порядок становится дополнительной информацией.

D
Сортировка

Сортировка — перестановка элементов массива так, чтобы для любых соседних позиций выполнялось \(a_i \le a_{i+1}\). Сами значения сохраняются, меняется только их порядок.

Для задач на пары чаще всего нужна сортировка по возрастанию. Она позволяет сравнить сумму крайних элементов с целью и понять, какой указатель нужно сдвинуть. Обычно сортировка занимает \(O(n\log n)\), а последующий проход — \(O(n)\).

\[T(n)=O(n\log n)+O(n)=O(n\log n)\]
T
Правило монотонности

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

Два указателя для поиска пары

Для поиска пары с суммой \(S\) поставим левый указатель \(L\) в начало массива, а правый \(R\) — в конец. Рассмотрим сумму \(a_L+a_R\). Если она меньше \(S\), нужно увеличить сумму: самый безопасный шаг — увеличить \(L\). Если сумма больше \(S\), уменьшаем её, сдвигая \(R\) влево. Если сумма равна \(S\), пара найдена.

\[a_L+a_R\begin{cases}<S,&L\leftarrow L+1\\>S,&R\leftarrow R-1\\=S,&\text{пара найдена}\end{cases}\]
T
Почему указатели не пропускают Шешім

Если \(a_L+a_R<S\), то для текущего \(L\) ни один элемент правее \(R\) не подходит: он ещё меньше или равен \(a_R\), значит сумма не увеличится до \(S\). Поэтому можно безопасно увеличить \(L\). Аналогично, при сумме больше \(S\) можно уменьшить \(R\).

Псевдокод
sort(a)
L = 0
R = n - 1
while L < R:
    s = a[L] + a[R]
    if s == S:
        вывести a[L], a[R]
        L = L + 1
        R = R - 1
    elif s < S:
        L = L + 1
    else:
        R = R - 1

Если требуется только ответ «есть ли пара», после найденной пары можно завершить алгоритм. Если нужно посчитать все пары, важно уточнить условие: считаются ли одинаковые значения одной группой, а элементы с одинаковыми значениями — разными экземплярами. Для такой обработки полезна обработка массива двумя указателями и отдельное сжатие одинаковых элементов.

Микро-проверка

Массив отсортирован: \([1,3,4,7,9]\), требуется сумма \(10\). Указатели стоят на \(1\) и \(9\). Что делаем после проверки суммы?

Разобранный пример: количество пар с ограничением

Тапсырма: дан отсортированный массив \([1,2,3,5,6,8,10]\). Сколько пар \((i,j)\), где \(i<j\), имеют сумму не больше \(10\)? Здесь не требуется перечислять только одну пару: нужно учесть все подходящие пары.

№
Идея подсчёта

Фиксируем левый индекс \(L\) и двигаем правый \(R\) от конца. Если \(a_L+a_R\le10\), то из-за сортировки подходят и все элементы между \(L+1\) и \(R\): их значения не больше \(a_R\). Значит, при таком \(R\) добавляется сразу \(R-L\) пар.

1
Начинаем с крайних элементов: \(L=0\), \(R=6\).
\(\displaystyle a_0+a_6=1+10=11>10\Rightarrow R\leftarrow5\)
2
Проверяем \(1+8=9\le10\). Все элементы от \(2\) до \(8\) справа также подходят.
\(\displaystyle \text{добавляем }R-L=5\text{ пар}\)
3
Переходим к следующему левому элементу и снова берём максимально возможный правый.
\(\displaystyle L\leftarrow1, a_1+a_5=2+8=10\Rightarrow\text{добавляем }5-1=4\)
4
Для \(L=2\) проверка \(3+8=11>10\), поэтому уменьшаем правый указатель.
\(\displaystyle R\leftarrow4, a_2+a_4=3+6=9\Rightarrow\text{добавляем }4-2=2\)
5
Для \(L=3\): \(5+6=11>10\), после уменьшения \(R\) станет равен \(L\), и пар больше нет.
\(\displaystyle 5+5\text{ не рассматривается, так как }i<j\)
\[\text{число пар при }a_L+a_R\le S=R-L\]

Всего получили \(5+4+2=11\) пар. Важен не сам набор чисел, а переход: при каждом увеличении \(L\) правый указатель не возвращается вправо. Поэтому после сортировки подсчёт выполняется за \(O(n)\).

Python
def count_pairs_at_most(a, limit):
    a.sort()
    left, right = 0, len(a) - 1
    answer = 0
    while left < right:
        if a[left] + a[right] <= limit:
            answer += right - left
            left += 1
        else:
            right -= 1
    return answer

Диапазоны и непрерывные группы

После сортировки удобно искать максимальный диапазон, в котором разность между крайним и первым элементом не превышает \(D\). Левый указатель обозначает начало текущего диапазона, правый — его конец. Пока \(a_R-a_L\le D\), расширяем диапазон вправо. Если условие нарушилось, двигаем \(L\) вправо, пока оно снова не станет верным.

\[a_R-a_L\le D\]

Так находят максимальное число элементов, укладывающихся в отрезок длины \(D\), число пар с разностью не больше \(D\), а также группы элементов, близких по значению. Если требуется обработать все одинаковые значения как одну группу, применяют приём обработки групп одинаковых элементов: указатель пропускает весь блок равных элементов.

D
Диапазон в отсортированном массиве

Диапазон — непрерывный фрагмент отсортированного массива \([L,R]\). Его ширина по значениям равна \(a_R-a_L\), а количество элементов — \(R-L+1\).

Для строк сортировка обычно выполняется не самих символов, а строк или пар «значение — исходный индекс». Если нужно сохранить исходные данные, используют сортировку по ключу. Для подсчёта серий одинаковых символов пригодится максимальная серия, а для группировки по условию — группировка по признаку.

LRa_R − a_L ≤ D
Текущий диапазон от указателя L до указателя R.

Типовые схемы и границы

  • Пара с точной суммой: при сравнении суммы с целью двигаем один из указателей; при совпадении фиксируем ответ.
  • Пара с суммой не больше цели: если крайняя пара подходит, добавляем сразу \(R-L\) пар и увеличиваем \(L\).
  • Максимальный диапазон: увеличиваем \(R\), а при нарушении условия сдвигаем \(L\) до восстановления условия.
  • Группы одинаковых элементов: находим левую границу группы, затем пропускаем все равные значения.
  • Тройка элементов: внешний цикл фиксирует первый элемент, а для оставшихся используется поиск пары; это связано со страницей поиск тройки элементов.
!
Частые ошибки

1. Использовать два указателя на неотсортированном массиве: доказательство монотонности тогда не работает. 2. Включить пару элемента с самим собой: условие обычно требует \(L<R\). 3. При подсчёте пар добавить одну пару вместо всех \(R-L\), когда крайняя пара подходит. 4. Перепутать разность индексов и разность значений: для диапазона нужно \(a_R-a_L\). 5. Забыть, что после сортировки изменились индексы; если нужны исходные позиции, храните их вместе со значениями.

Как выбрать направление

Сначала запишите, как меняется проверяемая величина при движении каждого указателя. Если увеличение \(L\) только увеличивает сумму, а уменьшение \(R\) только уменьшает её, схема подходит. Если оба указателя могут менять величину непредсказуемо, одного сортирования недостаточно.

Оценка сложности и подготовка ответа

Сортировка требует памяти и времени в зависимости от используемого алгоритма, но в экзаменационных решениях обычно достаточно указать \(O(n\log n)\). Два указателя делают не более \(n\) қадам каждым, поэтому их часть имеет сложность \(O(n)\). При ручном решении полезно выписать таблицу с \(L\), \(R\), значениями \(a_L\), \(a_R\) и результатом проверки.

УсловиеДействие при выполненииДействие при нарушении
a_L+a_R=Sзафиксировать парусдвинуть указатель по знаку сравнения
a_L+a_R≤Sдобавить R−L паруменьшить R
a_R−a_L≤Dрасширить вправоувеличить L
a_L=a_Rобработать группуперейти к следующему значению
Q
Жылдам тест по теме

Проверь себя

~ 2 мин4 вопроса
Вопрос 1 / 4
Вопрос 1 из 4 · сложность
Какова сложность сортировки и бір прохода двумя указателями?
Главное за минуту

Главное

  • Сначала сортируйте массив, если дальнейшее Шешім использует порядок значений.
  • Для точной суммы сравнивайте \(a_L+a_R\) с целью и сдвигайте один указатель.
  • Для подсчёта пар «сумма не больше» добавляйте сразу \(R-L\), когда крайняя пара подходит.
  • Для диапазона поддерживайте условие \(a_R-a_L\le D\) и двигайте указатели только вперёд.
  • Всегда проверяйте границу \(L<R\) и сохраняйте исходные индексы, если они нужны в ответе.