Swap без временной переменной
Условие
Напишите функцию, которая меняет местами значения двух переменных без использования временной переменной.
Сигнатура
func swap(a, b *int)
Требования
- Не использовать дополнительную переменную
- После вызова значения должны поменяться местами
Пример
x, y := 5, 10
swap(&x, &y)
fmt.Println(x, y) // 10 5
Бонус
Покажите несколько способов решения (арифметический, XOR, Go-идиоматический).
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Решение
Анализ задачи
Требования:
- Функция должна менять местами значения двух целых чисел
- Нельзя использовать дополнительную переменную
- Значения передаются по указателям
Бонус: несколько подходов — арифметический, побитовый XOR и идиоматический Go.
Решение 1: Арифметический способ
func swapArithmetic(a, b *int) {
*a = *a + *b
*b = *a - *b
*a = *a - *b
}
Как это работает:
- Шаг 1:
a = a + b(теперь a содержит сумму) - Шаг 2:
b = (a + b) - b = a(b получает старое значение a) - Шаг 3:
a = (a + b) - (a + b) - b = b(a получает старое значение b)
Пример: a=5, b=10
- Шаг 1: a = 5 + 10 = 15
- Шаг 2: b = 15 - 10 = 5
- Шаг 3: a = 15 - 5 = 10
Минусы: может привести к переполнению для больших чисел.
Решение 2: XOR (побитовое исключающее ИЛИ)
func swapXOR(a, b *int) {
*a = *a ^ *b
*b = *a ^ *b
*a = *a ^ *b
}
Как это работает:
a ^ a = 0иa ^ 0 = a(свойства XOR)- Шаг 1:
a = a ^ b - Шаг 2:
b = (a ^ b) ^ b = a(b получает старое значение a) - Шаг 3:
a = (a ^ b) ^ (a ^ b ^ b) = b(a получает старое значение b)
Пример: a=5 (0101), b=10 (1010)
- Шаг 1: a = 0101 ^ 1010 = 1111 (15)
- Шаг 2: b = 1111 ^ 1010 = 0101 (5)
- Шаг 3: a = 1111 ^ 0101 = 1010 (10)
Преимущества: работает со всеми целыми числами, нет переполнения.
Решение 3: Go-идиоматический способ
func swap(a, b *int) {
*a, *b = *b, *a
}
Это стандартный Go способ! Go позволяет множественное присваивание, поэтому временная переменная не нужна. Это самое читаемое и безопасное решение.
Преимущества:
- Максимальная читаемость
- Нет побочных эффектов (переполнение, потеря точности)
- Стиль Go
- Работает с любыми типами
Полный пример использования
package main
import "fmt"
func swapArithmetic(a, b *int) {
*a = *a + *b
*b = *a - *b
*a = *a - *b
}
func swapXOR(a, b *int) {
*a = *a ^ *b
*b = *a ^ *b
*a = *a ^ *b
}
func swapIdiomatic(a, b *int) {
*a, *b = *b, *a
}
func main() {
// Арифметический способ
x, y := 5, 10
swapArithmetic(&x, &y)
fmt.Printf("Arithmetic: x=%d, y=%d\\n", x, y) // 10, 5
// XOR способ
x, y = 5, 10
swapXOR(&x, &y)
fmt.Printf("XOR: x=%d, y=%d\\n", x, y) // 10, 5
// Идиоматический Go
x, y = 5, 10
swapIdiomatic(&x, &y)
fmt.Printf("Idiomatic: x=%d, y=%d\\n", x, y) // 10, 5
}
Рекомендация
В production коде используй идиоматический способ. Арифметический и XOR способы — интересная демонстрация знания битовых операций, но они менее читаемы и могут содержать ошибки. Go специально поддерживает множественное присваивание именно для таких задач.