← Назад к вопросам

Swap без временной переменной

2.0 Middle🔥 141 комментариев
#Основы Go

Условие

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

Сигнатура

func swap(a, b *int)

Требования

  • Не использовать дополнительную переменную
  • После вызова значения должны поменяться местами

Пример

x, y := 5, 10
swap(&x, &y)
fmt.Println(x, y) // 10 5

Бонус

Покажите несколько способов решения (арифметический, XOR, Go-идиоматический).

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Решение

Анализ задачи

Требования:

  • Функция должна менять местами значения двух целых чисел
  • Нельзя использовать дополнительную переменную
  • Значения передаются по указателям

Бонус: несколько подходов — арифметический, побитовый 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 специально поддерживает множественное присваивание именно для таких задач.

Swap без временной переменной | PrepBro