Как перевернуть строку с минимальными затратами

Ответ

В C++ для строки типа std::string самый эффективный и идиоматичный способ — использовать алгоритм std::reverse из стандартной библиотеки. Он выполняет in-place разворот за линейное время O(n) и константную дополнительную память O(1).

#include <algorithm>
#include <string>
#include <iostream>

int main() {
    std::string str = "Hello, World!";
    std::reverse(str.begin(), str.end());
    std::cout << str << std::endl; // Вывод: "!dlroW ,olleH"
    return 0;
}

Почему это минимальные затраты:

  • Время: O(n) — меньше нельзя, нужно посетить каждый символ.
  • Память: O(1) — алгоритм использует два итератора и меняет символы местами, не создавая новую строку.
  • Оптимизация: Реализация std::reverse в стандартной библиотеке часто использует оптимизации для конкретного компилятора.

Для C-строк (массивов char) принцип тот же, но реализуется вручную:

#include <cstring>

void reverse_c_string(char* str) {
    if (!str) return;
    char* end = str + strlen(str) - 1;
    while (str < end) {
        std::swap(*str, *end); // или ручной обмен через временную переменную
        ++str;
        --end;
    }
}

Ответ 18+ 🔞

А, ну вот, опять про разворот строки спрашивают. Ну, блядь, классика жанра, ебать мои старые костыли. Каждый второй джуниор на собеседовании с этим сталкивается, а потом в коде пишет какую-то дичь с созданием новой строки и конкатенацией в цикле, овердохуища памяти жрёт.

Так, слушай сюда, чувак. Всё проще, чем кажется. В C++ для std::string уже всё придумали за нас, умные дядьки. Не надо изобретать велосипед, который, кстати, будет кривой и на коленке собранный.

Самый правильный и быстрый способ — это взять и вызвать std::reverse. Это как взять и перевернуть бутерброд с колбасой — просто перекладываешь кусочки с одного края на другой, а не делаешь новый бутерброд из каждого кусочка хлеба отдельно, понимаешь?

Вот, смотри, как это выглядит в коде. Блоки кода я не трогаю, они святые.

#include <algorithm>
#include <string>
#include <iostream>

int main() {
    std::string str = "Hello, World!";
    std::reverse(str.begin(), str.end());
    std::cout << str << std::endl; // Вывод: "!dlroW ,olleH"
    return 0;
}

Вот и вся магия. Почему это оптимально? Да ёпта, потому что меньше никак! Алгоритм работает за O(n) — быстрее не получится, всё равно каждый символ ткнуть пальцем надо. А памяти он жрёт O(1), то есть практически ноль. Он просто берёт два итератора — один с начала, другой с конца — и меняет их местами, пока они не встретятся посередине. Никаких новых строк, никакого лишнего копирования. Красота!

А если у тебя вдруг старый добрый сишный массив char, то там, конечно, придётся немного покрутиться самому. Но принцип тот же — идёшь с двух концов и меняешь символы, пока не дойдёшь до середины. Главное — не забыть найти конец строки, а то так и будешь менять местами символы до скончания веков, пока не наткнёшься на случайный нуль-терминатор в памяти. Будет тебе хиросима и нигерсраки в одном флаконе.

#include <cstring>

void reverse_c_string(char* str) {
    if (!str) return;
    char* end = str + strlen(str) - 1;
    while (str < end) {
        std::swap(*str, *end); // или ручной обмен через временную переменную
        ++str;
        --end;
    }
}

Вот и весь сказ. Не усложняй, используй готовое. И да, чувак, доверия ебать ноль к тем, кто это вручную в десять строк пишет.