← Все вопросы

Как найти наибольшую палиндром-подстроку — Манакер или хеши с бинпоиском?

Задан 15 месяцев назад1.3к просмотров2 ответа
9

Классическая задача: дана строка до 10^6, найти самую длинную подстроку-палиндром. У меня два кандидата — Манакер за O(n) и хеши + бинпоиск по радиусу за O(n log n). Что выбрать и как из массива Манакера вытащить сам ответ (позиции)?

2 ответа

14
✓ Принятый ответ — помог автору

При n до 10^6 берите Манакер: O(n) и без риска коллизий. Хеши с бинпоиском (O(n log n)) проще написать на ходу, но на палиндромных задачах жюри любит анти-хеш тесты, плюс лишний логарифм по времени.

Из массивов Манакера ответ достаётся так: длина нечётного палиндрома с центром i равна 2*d1[i]-1, чётного — 2*d2[i]. Берём максимум и восстанавливаем границы.

pair<int,int> longest_palindrome(const string& s) {
    auto d1 = manacher_odd(s);
    // d2 — аналогично для чётных; опустим ради краткости
    int bestLen = 0, bestL = 0;
    for (int i = 0; i < (int)s.size(); ++i) {
        int len = 2 * d1[i] - 1;            // нечётный
        if (len > bestLen) { bestLen = len; bestL = i - d1[i] + 1; }
    }
    // не забыть пройтись по d2 для чётных палиндромов!
    return {bestL, bestL + bestLen - 1};   // [l, r] включительно
}

Итог: O(n) время, O(n) память. Главное — не забыть оба случая (нечёт и чёт), иначе на тесте abba потеряете ответ.

3

Если всё-таки хеши: бинпоиск по радиусу для каждого центра ищет максимальный k, при котором s[i-k..i+k] палиндром (через прямой/обратный хеш за O(1)). Корректно, но внимательно с чётным/нечётным центром: центров 2n-1. По коду это длиннее Манакера, парадоксально. Манакер тут просто лучше по всем осям, кроме «надо вспомнить, как пишется».

Ваш ответ

Войдите, чтобы ответить на вопрос.