Longest Palindromic Substring (LPS) in Linear Time and Constant Extra Space with Hashing

Revision en4, by dajeff, 2025-03-12 09:46:17

Many sources note that LPS can be solved in linearithmic time with hashing and binary search.

Surprisingly, I have not found any sources claiming that LPS can be solved in linear time with hashing, despite such an algorithm being possible and elementary. We'll introduce such an algorithm here.

#include <bits/stdc++.h>
 
using namespace std;
 
constexpr long long P = 31, INV = 357027418778899, MOD = 922320831845489;  // https://bigprimes.org/
 
pair<int, int> solve(string &s, bool odd) {
    long long lhash = 0, rhash = lhash, power = 1;
    int res = 1, resl = 0;
    for (int l = 0, r = odd ? 0 : 1; r < static_cast<int>(s.length());) {
        if (l >= 0 && lhash == rhash && s[l] == s[r]) {
            int potential = r - l + 1;
            if (potential > res) {
                res = potential;
                resl = l;
            }
 
            // extend
            lhash = (P * lhash + s[l--]) % MOD;
            rhash = (P * rhash + s[r++]) % MOD;
            power = (P * power) % MOD;
        } else {
            // shift
            lhash = static_cast<long long>((static_cast<__int128>(INV) * (lhash + power * s[((l + r) >> 1) + 1] - s[l + 1]) % MOD + MOD) % MOD);
            rhash = ((P * rhash - power * s[(l + r + 1) >> 1] + s[r]) % MOD + MOD) % MOD;
            ++l;
            ++r;
        }
    }
 
    return {resl, res};
}
 
int main() {
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
 
    string s;
    cin >> s;
 
    auto odd = solve(s, false), even = solve(s, true);
    cout << (odd.second >= even.second ? s.substr(odd.first, odd.second) : s.substr(even.first, even.second)) << endl;
 
    return 0;
}
Tags hashing, palindrome

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en8 English dajeff 2025-03-12 10:43:41 0 (published)
en7 English dajeff 2025-03-12 10:43:07 224 Tiny change: 'cases. If adding `s' -> 'cases. If extending our candidate window by adding `s'
en6 English dajeff 2025-03-12 10:37:05 1069
en5 English dajeff 2025-03-12 09:52:37 553 Tiny change: 'bbf58f/)\n```cpp\n' -> 'bbf58f/)\n\n```cpp\n'
en4 English dajeff 2025-03-12 09:46:17 0
en3 English dajeff 2025-03-12 09:46:17 1508
en2 English dajeff 2025-03-12 09:44:10 2372
en1 English dajeff 2025-02-25 23:01:50 2480 Initial revision (saved to drafts)