Развернуть строку без strrev
Условие
Напишите функцию, которая разворачивает строку без использования встроенной функции strrev().
Требования
- Функция принимает строку
- Возвращает перевёрнутую строку
- Нельзя использовать strrev()
- Корректная работа с UTF-8 строками
Примеры
reverseString("hello"); // "olleh"
reverseString("PHP"); // "PHP" (палиндром)
reverseString("Привет"); // "тевирП"
reverseString(""); // ""
Варианты реализации
- Через цикл
- Через рекурсию
- Через массив
Оцените сложность каждого подхода.
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Развернуть строку без strrev(): Полное решение
Анализ задачи
Задача требует реализации функции разворачивания строки без использования встроенной функции strrev(). Ключевой момент - корректная работа с UTF-8 строками, так как просто разворачивание массива символов в UTF-8 может привести к нарушению кодировки многобайтовых символов.
Подход 1: Через цикл с mb_substr
Преимущества:
- Корректная работа с UTF-8 символами
- Хорошая производительность для средних строк
- Простота понимания
- Временная сложность: O(n)
- Пространственная сложность: O(n)
function reverseString(string $string): string
{
$reversed = '';
$length = mb_strlen($string, 'UTF-8');
for ($i = $length - 1; $i >= 0; $i--) {
$reversed .= mb_substr($string, $i, 1, 'UTF-8');
}
return $reversed;
}
Тестирование:
echo reverseString("hello"); // olleh
echo reverseString("PHP"); // PHP
echo reverseString("Привет"); // тевирП
echo reverseString(""); // (пустая строка)
Подход 2: Через массив UTF-8 символов
Преимущества:
- Наиболее надежная работа с многобайтовыми символами
- Прямое использование функций работы с Unicode
- Временная сложность: O(n)
- Пространственная сложность: O(n)
function reverseString(string $string): string
{
// Разбиваем строку на UTF-8 символы
$chars = preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY);
// Разворачиваем массив символов
$chars = array_reverse($chars);
// Собираем обратно в строку
return implode('', $chars);
}
Альтернативный вариант с mb_strlen:
function reverseString(string $string): string
{
$reversed = '';
$length = mb_strlen($string, 'UTF-8');
for ($i = 1; $i <= $length; $i++) {
$reversed = mb_substr($string, -$i, 1, 'UTF-8') . $reversed;
}
return $reversed;
}
Подход 3: Через рекурсию
Преимущества:
- Элегантная реализация
- Демонстрирует понимание рекурсивного программирования
Недостатки:
- Медленнее циклов (особенно для длинных строк)
- Риск переполнения stack для очень длинных строк
- Временная сложность: O(n)
- Пространственная сложность: O(n) + call stack O(n)
function reverseString(string $string, int $index = 0): string
{
$length = mb_strlen($string, 'UTF-8');
// Базовый случай - пустая строка или исходим из конца
if ($index >= $length) {
return '';
}
// Рекурсивный вызов для оставшейся части + текущий символ
return reverseString($string, $index + 1) .
mb_substr($string, $index, 1, 'UTF-8');
}
Подход 4: Через обход строки в обратном направлении (производительный)
Самый оптимальный подход для очень длинных строк:
function reverseString(string $string): string
{
$result = '';
// Получаем длину в символах (не байтах)
$strLength = mb_strlen($string, 'UTF-8');
// Итерируем от конца к началу
for ($i = $strLength - 1; $i >= 0; $i--) {
$result .= mb_substr($string, $i, 1, 'UTF-8');
}
return $result;
}
Сравнение подходов
Таблица сложности:
| Подход | Память | Скорость | UTF-8 | Удобство |
|---|---|---|---|---|
| mb_substr цикл | O(n) | хорошо | да | простой |
| preg_split + reverse | O(n) | хорошо | да | простой |
| mb_substr рекурсия | O(n) | медленно | да | элегантный |
| array_reverse + implode | O(n) | быстро | да | простой |
Рекомендуемое решение для production
function reverseString(string $string): string
{
if (empty($string)) {
return '';
}
// Используем preg_split для универсальной работы с UTF-8
$chars = preg_split('//u', $string, -1, PREG_SPLIT_NO_EMPTY);
return implode('', array_reverse($chars));
}
Почему этот подход лучший:
- Полностью поддерживает многобайтовые UTF-8 символы
- Очень эффективен благодаря встроенным функциям
- Чистый и читаемый код
- Меньше всего ошибок
- Хорошая производительность
Полное тестирование
class ReverseStringTest
{
public function testSimpleEnglishString(): void
{
$this->assertEquals('olleh', reverseString('hello'));
}
public function testPalindrome(): void
{
$this->assertEquals('PHP', reverseString('PHP'));
}
public function testCyrillicString(): void
{
$this->assertEquals('тевирП', reverseString('Привет'));
}
public function testEmptyString(): void
{
$this->assertEquals('', reverseString(''));
}
public function testMixedUnicode(): void
{
$this->assertEquals('🎉olleh', reverseString('hello🎉'));
}
public function testSpecialCharacters(): void
{
$this->assertEquals('!dlrow olleH', reverseString('Hello world!'));
}
public function testMultibyteCharacters(): void
{
// Проверка корректности с различными Unicode символами
$string = '你好世界';
$reversed = reverseString($string);
$this->assertEquals('界世好你', $reversed);
}
}
Бенчмарк производительности
$testString = str_repeat('Привет ', 1000);
// Тест 1: mb_substr цикл
$start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
reverseString($testString); // mb_substr подход
}
$time1 = microtime(true) - $start;
// Тест 2: preg_split + array_reverse
$start = microtime(true);
for ($i = 0; $i < 10000; $i++) {
reverseString($testString); // preg_split подход
}
$time2 = microtime(true) - $start;
echo "mb_substr: {$time1}s\n";
echo "preg_split: {$time2}s\n";
Выводы
Выбор метода зависит от требований:
- Максимальная производительность: array_reverse с preg_split
- Максимальная совместимость: mb_substr в цикле
- Элегантность кода: array_reverse с preg_split
- Образовательная цель (рекурсия): рекурсивный подход
Для production-кода рекомендуется использовать подход с preg_split + array_reverse, так как он обеспечивает лучший баланс между производительностью, надежностью и читаемостью кода.