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

Развернуть строку без strrev

1.0 Junior🔥 151 комментариев
#PHP Core#Алгоритмы и структуры данных

Условие

Напишите функцию, которая разворачивает строку без использования встроенной функции strrev().

Требования

  • Функция принимает строку
  • Возвращает перевёрнутую строку
  • Нельзя использовать strrev()
  • Корректная работа с UTF-8 строками

Примеры

reverseString("hello");      // "olleh"
reverseString("PHP");        // "PHP" (палиндром)
reverseString("Привет");     // "тевирП"
reverseString("");           // ""

Варианты реализации

  • Через цикл
  • Через рекурсию
  • Через массив

Оцените сложность каждого подхода.

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

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

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

Развернуть строку без 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 + reverseO(n)хорошодапростой
mb_substr рекурсияO(n)медленнодаэлегантный
array_reverse + implodeO(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, так как он обеспечивает лучший баланс между производительностью, надежностью и читаемостью кода.