Нам дан массив входных данных, и у нас есть цель. Мы хотим найти, какие два элемента в массиве образуют значение, равное целевому.

Пример:
nums= [1,2,3,4,5,6,7]
цель = 10
вывод: [[3,7], [4,6]]

Ограничения.
Ограничение заключается в том, что числа должны быть отсортированы, чтобы применить две суммы.

Подход
То же, что и бинарный поиск (деление пополам), у нас есть два указателя, lptr и rptr.
lptr указывает на начальный индекс, а rptr — на последний индекс.

Теперь давайте посмотрим на представленную здесь закономерность:
Внимательно изучите эти два случая.

Случай 1.
Сохранение rptr постоянным и увеличение lptr
(1+7) → 8
(2+7) → 9
(3 +7) — —› 10
(4+7) — —› 11

Случай 2.
Сохранение lptr постоянным и увеличение rptr
(1+7) → 8
(1+6) → 7
(1 +5) → 6

Из приведенных выше двух случаев формируется шаблон, согласно которому при увеличении lptr сумма будет увеличиваться, и точно так же при увеличении rptr сумма будет уменьшаться (учитывая, что массив отсортирован).

Применение концепции
Теперь давайте применим этот подход к двум указателям, чтобы найти цель 10.
Шаг 1
Размещение lptr в индексе 0 и rptr по последнему индексу

nums = list([1,2,3,4,5,6,7])
target = 10

lptr = 0
rptr = len(nums)-1

main_ls = []

Шаг 2
Мы пройдемся по элементам

Теперь nums[lptr] + nums[rptr] = 8. Это меньше 10, что означает, что нам нужно увеличить сумму. Если увеличить сумму, то нам нужно переместить lptr.

Получается сумма 9. Снова нужно увеличить сумму.

Это сделано, получаем 10
nums[lptr] = 3 и nums[rptr] = 7. И nums[lptr]+nums[rptr]=10

Теперь нам не потребуются элементы, предшествующие lptr, и точно так же элементы, следующие за rptr. Таким образом мы увеличиваем lptr и уменьшаем rptr.

lptr += 1
rptr -= 1

Опять же, это формирует 10, и мы делаем lptr+=1 и rptr-=1.
Теперь мы видим, что lptr == rptr. Но в постановке задачи сказано, что сумма должна быть в виде двух разных элементов. Следовательно, мы прерываем итерацию.

Таким образом, вся логика такова:

while(lptr<rptr):
    two_sum =  nums[lptr]+nums[rptr]
    if  two_sum < target:
        lptr+=1
    elif two_sum > target:
        rptr-=1
    else:
        print([nums[lptr],nums[rptr]])
        lptr+=1
        rptr-=1
[3, 7]
[4, 6]

Теперь проблема в том, что если у нас есть повторяющиеся элементы в этих числах, мы не получим уникальный набор

nums = list([1,1,1,4,5,6,7,7])
target = 8

l = 0
r = len(nums)-1

main_ls = []



while(l<r):
    two_sum =  nums[l]+nums[r]
    if  two_sum < target:
        l+=1
    elif two_sum > target:
        r-=1
    else:
        print([nums[l],nums[r]])
        l+=1
        r-=1
[1, 7]
[1, 7]

Теперь, чтобы справиться с этим, мы должны увеличиваться до тех пор, пока не появятся такие повторяющиеся элементы.

Таким образом, мы сохраняем условие, что
пока nums[l] == prev и l‹r: l+=1
и таким же образом
while nums[r] == prev2 и l‹r : г-=1

Таким образом, вся логика выглядит так, а тестирование на одном случае драйвера

nums = list([1,1,1,1,7,7,7,7])
target = 8

l = 0
r = len(nums)-1

main_ls = []



while(l<r):
    two_sum =  nums[l]+nums[r]
    if  two_sum < target:
        prev = nums[l]
        while nums[l] == prev and l<r: l+=1
    elif two_sum > target:
        prev = nums[r]
        while nums[r] == prev and l<r: r-=1
    else:
        print(nums[l],nums[r])
        prev1 = nums[l]
        prev2 = nums[r]
        while nums[l] == prev1 and l<r: l+=1
        while nums[r] == prev2 and l<r: r-=1
1 7

Примечание. Это не повлияет на общую временную сложность. Остается только O(n).

Спасибо, что прочитали мою статью!!!

Директ открыт для любых вопросов!!! (https://linktr.ee/prituldave)