Как поменять местами две целочисленные переменные без использования третьей переменной и синтаксического сахара Python
Что проверяют
Знаете ли вы арифметический и побитовый приём и понимаете ли, где они ломаются. Задача с подвохом: следом спрашивают, почему в настоящем коде на Python так не пишут и что будет с дробными числами.
Как отвечать
Два классических способа:
a = a + b
b = a - b
a = a - b
a = a ^ b
b = a ^ b
a = a ^ bАрифметический работает так: после первой строки в a лежит сумма, вычитая b, получаем старое a, вычитая новое b из суммы, получаем старое b. XOR опирается на то, что x ^ x == 0 и x ^ 0 == x, поэтому повторное применение отменяет первое.
Дальше то, что отличает хороший ответ:
- переполнения нет:
intв Python произвольной точности, сумма не переполнится, в отличие от C, где переполнение знакового целого это неопределённое поведение. XOR в Python работает и с отрицательными числами; - памяти вы не экономите: каждое промежуточное значение это новый объект
int, а на больших числах сложение и XOR идут за время, пропорциональное их длине; - только целые: для
floatXOR даётTypeError, а арифметика теряет точность; - вариант с умножением:
a = a * b, затем деление//падает на нуле, как рабочий его лучше не предлагать.
Закончите тем, что в продакшене пишут a, b = b, a. Это читается сразу, и для двух переменных CPython компилирует такую запись в перестановку значений на стеке, без создания кортежа.
Где спотыкаются
Не видят проблемы общего места хранения. Если менять через XOR элементы arr[i] и arr[j] при i == j, первая же операция запишет туда ноль, и ноль там останется. Арифметический способ в этом случае ломается так же. Одинаковые значения в разных переменных проблем не создают.
Утверждают, что трюк быстрее или экономнее обычного обмена. В Python верно обратное: три операции с созданием объектов против одной перестановки.
Переносят рассуждения из C и начинают объяснять переполнение для Python, где его нет, или, наоборот, забывают о нём, когда интервьюер просит тот же приём на C или Go.