В программировании часто встречаются задачи, которые кажутся элементарными, пока не попробуешь реализовать их без встроенных средств языка. Одна из таких задач — преобразование числа в строку без использования стандартных библиотечных функций.
Давайте разберем элегантное решение, которое можно уверенно показать на техническом собеседовании.
Понимание задачи
Нам нужно написать функцию, которая принимает целое число (integer) и возвращает его строковое представление. Например:
123→"123"-456→"-456"0→"0"
Ограничения: нельзя использовать встроенные функции преобразования StringBuilder и пакет fmt (кроме тестов).
Ключевые аспекты решения
Основная сложность этой задачи заключается в том, что мы работаем с отдельными цифрами числа, а не с числом как единым целым. Цифры в числе имеют разный вес: единицы, десятки, сотни и т.д. Нам нужно:
- Извлекать цифры числа по одной, начиная с конца.
- Преобразовать каждую цифру в соответствующий символ.
- Корректно обрабатывать отрицательные числа.
- Особо обрабатывать ноль.
- Собирать все символы в правильном порядке.
Пошаговое решение
Шаг 1: Обработка особых случаев
Первым делом обработаем два особых случая — ноль и отрицательные числа:
func IntToString(num int) string {
// особый случай: ноль
if num == 0 {
return "0"
}
// определяем, является ли число отрицательным
isNegative := false
if num < 0 {
isNegative = true
num = -num // работаем с положительным числом
}
}
Шаг 2: Подготовка к извлечению цифр
Нам понадобится временный массив для хранения цифр в обратном порядке (поскольку мы извлекаем цифры с конца):
// создаем массив для хранения символов // (максимальная длина в int в 64-битной системе - 20 символов) const maxDigits = 20 temp := make([]byte, maxDigits) index := 0
Шаг 3: Извлечение цифр
Извлекаем цифры числа по одной, начиная с младшего разряда:
// извлекаем цифры по одной, начиная с конца
for num > 0 {
digit := num % 10 // получаем последнюю цифру
temp[index] = byte('0' + digit) // преобразуем цифру в символ
index++
num /= 10 // убираем последнюю цифру из числа
}
Здесь используется важный трюк: в Go символы представляются числами (кодами Unicode), и цифры идут последовательно. Поэтому '0' + digit дает нам символ, соответствующий цифре.
Шаг 4: Формирование результата
Теперь у нас есть цифры в обратном порядке, нужно создать итоговую строку:
// вычисляем длину результата
length := index
if isNegative {
length++ // добавляем место для знака минус
}
// создаем байтовый слайс для результата
result := make([]byte, length)
// добавляем знак минус, если необходимо
resultIndex := 0
if isNegative {
result[0] = '-'
result = 1
}
// записываем цифры в правильном порядке
// (извлекли с конца, поэтому переворачиваем)
for i := index - 1; i >= 0; i-- {
result[resultIndex] = temp[i]
resultIndex++
}
Полный код функции
func IntToString(num int) string {
// обработка нуля
if num == 0 {
return "0"
}
// обработка отрицательных чисел
isNegative := false
if num < 0 {
isNegative = true
num = -num
}
// временное хранилище для цифр (в обратном порядке)
const maxDigits = 20
temp := make([]byte, maxDigits)
index := 0
// извлечение цифр
for num > 0 {
digit := num % 10
temp[index] = byte('0' + digit)
index++
num /= 10
}
// формирование результата
length := index
if isNegative {
length++
}
result := make([]byte, length)
resultIndex := 0
if isNegative {
result[0] = '-'
resultIndex = 1
}
// переворачиваем цифры (извлекли с конца)
for i := index - 1; i >= 0; i-- {
result[resultIndex] = temp[i]
resultIndex++
}
return string(result)
}
Тестирование решения
Для тестирования можно использовать простые тесты в отдельном файле:
package main
import "testing"
func TestIntToString(t *testing.T) {
tests := []struct {
name string
input int
expected string
}{
{"positive number", 123, "123"},
{"negative number", -456, "-456"},
{"zero", 0, "0"},
{"large positive", 987654321, "987654321"},
{"large negative", -987654321, "-987654321"},
{"minimum positive", 1, "1"},
{"minimum negative", -1, "-1"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := IntToString(tt.input)
if result != tt.expected {
t.Errorf("IntToString(%d) = %s, expected %s",
tt.input, result, tt.expected)
}
})
}
}
Почему это решение хорошее?
- Полное понимание процесса: решение демонстрирует, что вы понимаете, как работают числа на низком уровне.
- Обработка граничных случаев: учтены ноль, отрицательные числа, минимальное и максимальное значения.
- Эффективность: алгоритм работает за
O(n), гдеn— количество цифр в числе. - Память: используется фиксированный объем дополнительной памяти.
- Читаемость: код хорошо структурирован и легко читается.
Ключевой вывод
Задача преобразования числа в строку — отличный пример того, как простое на первый взгляд задание позволяет оценить фундаментальные знания программиста. Представленное решение показывает понимание основ работы с числами, строками и алгоритмами.
А какие оптимизации или улучшения для этой задачи можете предложить вы? Поделитесь своими мыслями в комментариях.