Разверните строку так, чтобы многобайтовые символы UTF-8 остались целыми
Реализуйте reverse(s), возвращающую s с символами в обратном порядке. Требование: многобайтовые символы UTF-8 должны остаться целыми — разворот сырых байтов разрезал бы руну вроде é и дал бы невалидный UTF-8. O(n) по времени. Пример: reverse("héllo") → "olléh".
func reverse(s string) string {
// ваш код здесь
return ""
}
Допишите реализацию.
Сначала преобразуйте строку в []rune, затем меняйте местами с двух концов двумя указателями и верните string(r). Работа по рунам сохраняет многобайтовые символы целыми — разворот сырых байтов разрезал бы руну вроде é и испортил бы её. Алгоритм O(n) по времени и O(n) по памяти.
- ✗Разворачивать
[]byteвместо[]rune, разрезая многобайтовые символы - ✗Считать, что
rangeидёт по строке в обратном порядке - ✗Индексировать
s[i]и трактовать каждый байт как символ
- →Почему разворот байтового среза строки
hélloдаёт невалидный UTF-8? - →Как развернуть по графемным кластерам (например, эмодзи с комбинирующими знаками)?
Задача
Развернуть строку, корректно обработав Unicode: многобайтовые символы должны остаться целыми.
func reverse(s string) string {
r := []rune(s) // работаем по рунам, а не байтам
for i, j := 0, len(r)-1; i < j; i, j = i+1, j-1 {
r[i], r[j] = r[j], r[i]
}
return string(r)
}
// reverse("héllo") -> "olléh" (разворот байтов испортил бы "é")
Почему по рунам
Строка в Go — это байты в UTF-8. Символ é занимает два байта. Если разворачивать []byte, два байта é поменяются местами по отдельности и дадут невалидную последовательность UTF-8 — символ разрушится.
Преобразование []rune(s) декодирует строку в кодовые точки, поэтому каждый символ — один элемент. Два указателя меняют элементы с концов к центру за O(n); string(r) снова кодирует руны в UTF-8.
⚠️ Это проверяет понимание того, что строка — последовательность байтов, и что многобайтовые символы нужно разворачивать как руны.