namespace v1
{
namespace details
{
inline bool is_palindromic(int i, int j, std::vector<std::vector<std::pair<int, int>>> & cache)
{
std::pair<int, int> deux = cache[i][j];
return (deux.first == i && deux.second == j);
}
inline int get_distance(std::pair<int, int> deux)
{
return (deux.second - deux.first + 1);
}
}
std::string get_longest_palindromic_substring(const char * input)
{
std::string ret;
int n = static_cast<int>(input != NULL ? strlen(input) : 0);
if (n > 1) {
std::vector<std::vector<std::pair<int, int>>> cache(n, std::vector<std::pair<int, int>>(n));
for (int i = 0; i < n; ++i) {
cache[i][i].first = i;
cache[i][i].second = i;
}
for (int i = 0, ie = n - 1; i < ie; ++i) {
int j = i + 1;
cache[i][j] = input[i] == input[j] ? std::make_pair(i, j) : cache[i][i];
}
for (int d = 2; d < n; ++d) {
for (int i = 0, ie = n - d; i < ie; ++i) {
int j = i + d;
int ni = i + 1, nj = j - 1;
auto c1 = cache[ ni ][ j ];
if ( details::get_distance( cache[ i ][ nj ] ) > details::get_distance( cache[ ni ][ j ] ) ) {
c1 = cache[ i ][ nj ];
}
if ( input[ i ] == input[ j ] ) {
auto c2 = cache[ ni ][ nj ];
if ( details::is_palindromic( ni, nj, cache ) ) {
c2 = std::make_pair( i, j );
}
if ( details::get_distance( c1 ) < details::get_distance( c2 ) ) {
c1 = c2;
}
}
cache[i][j] = c1;
}
}
auto deux = cache[0][n - 1];
ret.assign(input + deux.first, input + deux.second + 1);
}
else if (n == 1) {
ret.push_back(input[0]);
}
return std::move(ret);
}
}
namespace v2
{
namespace details
{
std::pair<int, int> get_palindromic_substring(int first, int second, const char * input, int n)
{
while (first > -1 && second < n && input[first] == input[second]) {
--first;
++second;
}
return std::make_pair(first + 1, second - 1);
}
bool larger(std::pair<int, int> p1, std::pair<int, int> p2)
{
int d1 = p1.second - p1.first + 1;
int d2 = p2.second - p2.first + 1;
return d1 > d2;
}
}
std::string get_longest_palindromic_substring(const char * input)
{
int n = static_cast<int>(input != NULL ? strlen(input) : 0);
std::string ret;
if (n > 1) {
std::pair<int, int> section = { 0, -1 };
for (int i = 1, ie = n * 2; i < ie; ++i) {
int second = i / 2;
int first = second - (((i & 1) + 1) & 1);
auto result = details::get_palindromic_substring(first, second, input, n);
//printf( "%s\n", std::string( input + result.first, input + result.second + 1 ).c_str() );
if ( details::larger( result, section ) ) {
section = result;
}
}
ret.assign(input + section.first, input + section.second + 1);
}
else if (n == 1) {
ret.push_back(input[0]);
}
return std::move(ret);
}
}
namespace v3
{
namespace details
{
std::vector<char> pre_process(const char * input)
{
assert(input != NULL && input[0] != 0);
size_t n = strlen(input);
std::vector<char> ret;
ret.reserve((n + 1) * 2);
for (; *input != 0; ++input) {
ret.push_back( '\0' );
ret.push_back( input[ 0 ] );
}
ret.push_back( '\0' );
return std::move( ret );
}
}
std::string get_longest_palindromic_substring(const char * input)
{
int n = static_cast<int>(input != NULL ? strlen(input) : 0);
std::string ret;
if (n > 1) {
std::vector<char> data(details::pre_process(input));
n = static_cast<int>(data.size());
std::vector<int> cache(n, 0);
int center = 0, right = 0, i, l;
for (i = 1, --n; i < n; ++i) {
int mi = center * 2 - i;
cache[i] = i < right ? std::min(right - i, cache[mi]) : 0;
l = cache[i];
int il = i - cache[i] - 1, ir = i + cache[i] + 1;
while (il > -1 && ir < n && data[il] == data[ir]) {
--il;
++ir;
++l;
}
cache[i] = l;
--ir;
if ( ir > right ) {
right = ir;
center = i;
}
}
l = 0;
for (i = 0; i < n; ++i) {
if (cache[i] > l) {
l = cache[i];
center = i;
}
}
i = center / 2;
l /= 2;
ret.assign(input + i - l, input + i + l + (center & 1));
}
else if (n == 1) {
ret.push_back(input[0]);
}
return std::move(ret);
}
}