Longest Palindromic Substring
Last Updated :
30 Jul, 2025
Given a string s, find the longest substring which is a palindrome. If there are multiple answers, then find the first appearing substring.
Examples:
Input: s = "forgeeksskeegfor"
Output: "geeksskeeg"
Explanation: The longest substring that reads the same forward and backward is "geeksskeeg". Other palindromes like "kssk" or "eeksskee" are shorter.
Input: s = "Geeks"
Output: "ee"
Explanation: The substring "ee" is the longest palindromic part in "Geeks". All others are shorter single characters.
Input: s = "abc"
Output: "a"
Explanation: No multi-letter palindromes exist. So the first character "a" is returned as the longest palindromic substring.
[Naive Approach] Generating all sub-strings - O(n3) time and O(1) space
Generate all possible substrings of the given string. For each substring, check if it is a palindrome.
If it is, update the result if its length is greater than the longest palindrome found so far.
C++
#include <iostream>
using namespace std;
// function to check if a substring
// s[low..high] is a palindrome
bool checkPal(string &s, int low, int high) {
while (low < high) {
if (s[low] != s[high])
return false;
low++;
high--;
}
return true;
}
// function to find the longest palindrome substring
string getLongestPal(string& s) {
int n = s.size();
// all substrings of length 1 are palindromes
int maxLen = 1, start = 0;
// nested loop to mark start and end index
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// check if the current substring is
// a palindrome
if (checkPal(s, i, j) && (j - i + 1) > maxLen) {
start = i;
maxLen = j - i + 1;
}
}
}
return s.substr(start, maxLen);
}
int main() {
string s = "forgeeksskeegfor";
cout << getLongestPal(s) << endl;
return 0;
}
Java
class GfG {
// function to check if a substring
// s[low..high] is a palindrome
static boolean checkPal(String s, int low, int high) {
while (low < high) {
if (s.charAt(low) != s.charAt(high))
return false;
low++;
high--;
}
return true;
}
// function to find the longest palindrome substring
static String getLongestPal(String s) {
int n = s.length();
// all substrings of length 1 are palindromes
int maxLen = 1, start = 0;
// nested loop to mark start and end index
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// check if the current substring is
// a palindrome
if (checkPal(s, i, j) && (j - i + 1) > maxLen) {
start = i;
maxLen = j - i + 1;
}
}
}
return s.substring(start, start + maxLen);
}
public static void main(String[] args) {
String s = "forgeeksskeegfor";
System.out.println(getLongestPal(s));
}
}
Python
# function to check if a substring
# s[low..high] is a palindrome
def checkPal(str, low, high):
while low < high:
if str[low] != str[high]:
return False
low += 1
high -= 1
return True
# function to find the longest palindrome substring
def getLongestPal(s):
n = len(s)
# all substrings of length 1 are palindromes
maxLen = 1
start = 0
# nested loop to mark start and end index
for i in range(n):
for j in range(i, n):
# check if the current substring is
# a palindrome
if checkPal(s, i, j) and (j - i + 1) > maxLen:
start = i
maxLen = j - i + 1
return s[start:start + maxLen]
if __name__ == "__main__":
s = "forgeeksskeegfor"
print(getLongestPal(s))
C#
using System;
class GfG {
// function to check if a substring
// s[low..high] is a palindrome
static bool checkPal(string s, int low, int high) {
while (low < high) {
if (s[low] != s[high])
return false;
low++;
high--;
}
return true;
}
// function to find the longest palindrome substring
static string getLongestPal(string s) {
int n = s.Length;
// all substrings of length 1 are palindromes
int maxLen = 1, start = 0;
// nested loop to mark start and end index
for (int i = 0; i < n; i++) {
for (int j = i; j < n; j++) {
// check if the current substring is
// a palindrome
if (checkPal(s, i, j) && (j - i + 1) > maxLen) {
start = i;
maxLen = j - i + 1;
}
}
}
return s.Substring(start, maxLen);
}
static void Main(string[] args) {
string s = "forgeeksskeegfor";
Console.WriteLine(getLongestPal(s));
}
}
JavaScript
// function to check if a substring
// s[low..high] is a palindrome
function checkPal(s, low, high) {
while (low < high) {
if (s[low] !== s[high])
return false;
low++;
high--;
}
return true;
}
// function to find the longest palindrome substring
function getLongestPal(s) {
const n = s.length;
// all substrings of length 1 are palindromes
let maxLen = 1, start = 0;
// nested loop to mark start and end index
for (let i = 0; i < n; i++) {
for (let j = i; j < n; j++) {
// check if the current substring is
// a palindrome
if (checkPal(s, i, j) && (j - i + 1) > maxLen) {
start = i;
maxLen = j - i + 1;
}
}
}
return s.substring(start, start + maxLen);
}
// Driver Code
const s = "forgeeksskeegfor";
console.log(getLongestPal(s));
[Better Approach - 1] Using Dynamic Programming - O(n2) time and O(n2) space
The idea is to use Dynamic Programming to store the status of smaller substrings and use these results to check if a longer substring forms a palindrome.
- The main idea behind the approach is that if we know the status (i.e., palindrome or not) of the substring ranging [i, j], we can find the status of the substring ranging [i-1, j+1] by only matching the character str[i-1] and str[j+1].
- If the substring from i to j is not a palindrome, then the substring from i-1 to j+1 will also not be a palindrome. Otherwise, it will be a palindrome only if str[i-1] and str[j+1] are the same.
- Base on this fact, we can create a 2D table (say table[][] which stores status of substring str[i . . . j] ), and check for substrings with length from 1 to n. For each length find all the substrings starting from each character i and find if it is a palindrome or not using the above idea. The longest length for which a palindrome formed will be the required answer.
Note: Refer to Longest Palindromic Substring using Dynamic Programming for detailed approach.
C++
#include <iostream>
#include <vector>
using namespace std;
string getLongestPal(string s) {
int n = s.size();
vector<vector<bool>> dp(n, vector<bool>(n, false));
// dp[i][j] if the substring from [i to j]
// is a palindrome or not
int start = 0, maxLen = 1;
// all substrings of length 1 are palindromes
for (int i = 0; i < n; ++i) dp[i][i] = true;
// check for substrings of length 2
for (int i = 0; i < n - 1; ++i) {
if (s[i] == s[i+1]) {
dp[i][i+1] = true;
if(maxLen==1){
start = i;
maxLen = 2;
}
}
}
// check for substrings of length 3 and more
for (int len = 3; len <= n; ++len) {
for (int i = 0; i <= n - len; ++i) {
int j = i + len - 1;
// if s[i] == s[j] then check for
// i [i+1 --- j-1] j
if (s[i] == s[j] && dp[i+1][j-1]) {
dp[i][j] = true;
if(len>maxLen){
start = i;
maxLen = len;
}
}
}
}
return s.substr(start, maxLen);
}
int main() {
string s = "forgeeksskeegfor";
cout << getLongestPal(s) << endl;
}
Java
class GfG {
public static String getLongestPal(String s) {
int n = s.length();
boolean[][] dp = new boolean[n][n];
// dp[i][j] if the substring from [i to j]
// is a palindrome or not
int start = 0, maxLen = 1;
// all substrings of length 1 are palindromes
for (int i = 0; i < n; ++i) dp[i][i] = true;
// check for substrings of length 2
for (int i = 0; i < n - 1; ++i) {
if (s.charAt(i) == s.charAt(i + 1)) {
dp[i][i + 1] = true;
if(maxLen == 1){
start = i;
maxLen = 2;
}
}
}
// check for substrings of length 3 and more
for (int len = 3; len <= n; ++len) {
for (int i = 0; i <= n - len; ++i) {
int j = i + len - 1;
// if s[i] == s[j] then check for
// i [i+1 --- j-1] j
if (s.charAt(i) == s.charAt(j) && dp[i + 1][j - 1]) {
dp[i][j] = true;
if(len > maxLen){
start = i;
maxLen = len;
}
}
}
}
return s.substring(start, start + maxLen);
}
public static void main(String[] args) {
String s = "forgeeksskeegfor";
System.out.println(getLongestPal(s));
}
}
Python
def getLongestPal(s):
n = len(s)
dp = [[False] * n for _ in range(n)]
# dp[i][j] if the substring from [i to j] is a palindrome or not
start = 0
maxLen = 1
# all substrings of length 1 are palindromes
for i in range(n):
dp[i][i] = True
# check for substrings of length 2
for i in range(n - 1):
if s[i] == s[i + 1]:
dp[i][i + 1] = True
if maxLen == 1:
start = i
maxLen = 2
# check for substrings of length 3 and more
for length in range(3, n + 1):
for i in range(n - length + 1):
j = i + length - 1
# if s[i] == s[j] then check for [i+1 .. j-1]
if s[i] == s[j] and dp[i + 1][j - 1]:
dp[i][j] = True
if length > maxLen:
start = i
maxLen = length
return s[start:start + maxLen]
if __name__ == "__main__":
s = "forgeeksskeegfor"
print(getLongestPal(s))
C#
using System;
class GfG {
static string getLongestPal(string s) {
int n = s.Length;
bool[,] dp = new bool[n, n];
// dp[i][j] if the substring from [i to j]
// is a palindrome or not
int start = 0, maxLen = 1;
// all substrings of length 1 are palindromes
for (int i = 0; i < n; ++i) dp[i, i] = true;
// check for substrings of length 2
for (int i = 0; i < n - 1; ++i) {
if (s[i] == s[i + 1]) {
dp[i, i + 1] = true;
if (maxLen == 1) {
start = i;
maxLen = 2;
}
}
}
// check for substrings of length 3 and more
for (int len = 3; len <= n; ++len) {
for (int i = 0; i <= n - len; ++i) {
int j = i + len - 1;
// if s[i] == s[j] then check for
// i [i+1 --- j-1] j
if (s[i] == s[j] && dp[i + 1, j - 1]) {
dp[i, j] = true;
if (len > maxLen) {
start = i;
maxLen = len;
}
}
}
}
return s.Substring(start, maxLen);
}
public static void Main(string[] args) {
string s = "forgeeksskeegfor";
Console.WriteLine(getLongestPal(s));
}
}
JavaScript
function getLongestPal(s) {
let n = s.length;
const dp = Array.from({ length: n }, () => new Uint8Array(n));
// dp[i][j] if the substring from [i to j]
// is a palindrome or not
let start = 0, maxLen = 1;
// all substrings of length 1 are palindromes
for (let i = 0; i < n; ++i) dp[i][i] = true;
// check for substrings of length 2
for (let i = 0; i < n - 1; ++i) {
if (s[i] === s[i + 1]) {
dp[i][i + 1] = true;
if (maxLen === 1) {
start = i;
maxLen = 2;
}
}
}
// check for substrings of length 3 and more
for (let len = 3; len <= n; ++len) {
for (let i = 0; i <= n - len; ++i) {
let j = i + len - 1;
// if s[i] == s[j] then check for
// i [i+1 --- j-1] j
if (s[i] === s[j] && dp[i + 1][j - 1]) {
dp[i][j] = true;
if (len > maxLen) {
start = i;
maxLen = len;
}
}
}
}
return s.substring(start, start + maxLen);
}
// Driver Code
let s = "forgeeksskeegfor";
console.log(getLongestPal(s));
[Better Approach - 2] Using Expansion from center - O(n2) time and O(1) space
The idea is to traverse each character in the string and treat it as a potential center of a palindrome, trying to expand around it in both directions while checking if the expanded substring remains a palindrome.
=> For each position, we check for both odd-length palindromes (where the current character is the center) and even-length palindromes (where the current character and the next character together form the center).
=> As we expand outward from each center, we keep track of the start position and length of the longest palindrome found so far, updating these values whenever we find a longer valid palindrome.
Step-by-step approach:
- Iterate through each character in the string, treating it as the center of a potential palindrome.
- For each center, expand in two ways: one for odd-length palindromes (center at index i) and one for even-length palindromes (center between indices i and i+1)
- Use two pointers low and high to track the left and right boundaries of the current palindrome.
- While low and high are in bounds and s[low] == s[high], expand outward.
- If the current palindrome length (high - low + 1) is greater than the previous maximum, update the starting index and max length.
- After checking all centers, return the substring starting at start with length maxLen.
C++
#include <iostream>
using namespace std;
string getLongestPal(string &s) {
int n = s.length();
int start = 0, maxLen = 1;
for (int i = 0; i < n; i++) {
// this runs two times for both odd and even
// length palindromes.
// j = 0 means odd and j = 1 means even length
for (int j = 0; j <= 1; j++) {
int low = i;
int high = i + j;
// expand substring while it is a palindrome
// and in bounds
while (low >= 0 && high < n && s[low] == s[high])
{
int currLen = high - low + 1;
if (currLen > maxLen) {
start = low;
maxLen = currLen;
}
low--;
high++;
}
}
}
return s.substr(start, maxLen);
}
int main() {
string s = "forgeeksskeegfor";
cout << getLongestPal(s) << endl;
return 0;
}
Java
class GfG {
static String getLongestPal(String s) {
int n = s.length();
int start = 0, maxLen = 1;
for (int i = 0; i < n; i++) {
// this runs two times for both odd and even
// length palindromes.
// j = 0 means odd and j = 1 means even length
for (int j = 0; j <= 1; j++) {
int low = i;
int high = i + j;
// expand substring while it is a palindrome
// and in bounds
while (low >= 0 && high < n && s.charAt(low) == s.charAt(high))
{
int currLen = high - low + 1;
if (currLen > maxLen) {
start = low;
maxLen = currLen;
}
low--;
high++;
}
}
}
return s.substring(start, start + maxLen);
}
public static void main(String[] args) {
String s = "forgeeksskeegfor";
System.out.println(getLongestPal(s));
}
}
Python
def getLongestPal(s):
n = len(s)
start, maxLen = 0, 1
for i in range(n):
# this runs two times for both odd and even
# length palindromes.
# j = 0 means odd and j = 1 means even length
for j in range(2):
low, high = i, i + j
# expand substring while it is a palindrome
# and in bounds
while low >= 0 and high < n and s[low] == s[high]:
currLen = high - low + 1
if currLen > maxLen:
start = low
maxLen = currLen
low -= 1
high += 1
return s[start:start + maxLen]
if __name__ == "__main__":
s = "forgeeksskeegfor"
print(getLongestPal(s))
C#
using System;
class GfG {
static string getLongestPal(string s) {
int n = s.Length;
int start = 0, maxLen = 1;
for (int i = 0; i < n; i++) {
// this runs two times for both odd and even
// length palindromes.
// j = 0 means odd and j = 1 means even length
for (int j = 0; j <= 1; j++) {
int low = i;
int high = i + j;
// expand substring while it is a palindrome
// and in bounds
while (low >= 0 && high < n && s[low] == s[high])
{
int currLen = high - low + 1;
if (currLen > maxLen) {
start = low;
maxLen = currLen;
}
low--;
high++;
}
}
}
return s.Substring(start, maxLen);
}
static void Main(string[] args) {
string s = "forgeeksskeegfor";
Console.WriteLine(getLongestPal(s));
}
}
JavaScript
function getLongestPal(s) {
const n = s.length;
let start = 0, maxLen = 1;
for (let i = 0; i < n; i++) {
// this runs two times for both odd and even
// length palindromes.
// j = 0 means odd and j = 1 means even length
for (let j = 0; j <= 1; j++) {
let low = i;
let high = i + j;
// expand substring while it is a palindrome
// and in bounds
while (low >= 0 && high < n && s[low] === s[high])
{
const currLen = high - low + 1;
if (currLen > maxLen) {
start = low;
maxLen = currLen;
}
low--;
high++;
}
}
}
return s.substring(start, start + maxLen);
}
// Driver Code
const s = "forgeeksskeegfor";
console.log(getLongestPal(s));
[Expected Approach] Using Manacher’s Algorithm - O(n) time and O(n) space
The idea is to use Manacher’s algorithm, which transforms the input string by inserting separators (#) and sentinels to handle both even and odd-length palindromes uniformly.
For each position in the transformed string, we expand the longest possible palindrome centered there using mirror symmetry and previously computed values.
This expansion is bounded efficiently using the rightmost known palindrome range to avoid redundant checks.
Whenever a longer palindrome is found, we update its length and starting index in the original string.
C++
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class manacher {
public:
// p[i] stores the radius of the palindrome
// centered at position i in ms
vector<int> p;
// transformed string with sentinels
// and separators
string ms;
manacher(string &s) {
// left sentinel to avoid bounds check
ms = "@";
for (char c : s) {
// insert '#' between every character
ms += "#" + string(1, c);
}
// right sentinel
ms += "#$";
runManacher();
}
void runManacher() {
int n = ms.size();
p.assign(n, 0);
int l = 0, r = 0;
for (int i = 1; i < n - 1; ++i) {
// initialize p[i] based on its mirror
// and current [l, r] range
if(r + l - i >= 0 && r + l - i < n)
p[i] = max(0, min(r - i, p[r + l - i]));
// try expanding around center i
while (ms[i + 1 + p[i]] == ms[i - 1 - p[i]]) {
++p[i];
}
// update [l, r] if the new palindrome goes
// beyond current right boundary
if (i + p[i] > r) {
l = i - p[i];
r = i + p[i];
}
}
}
// return the radius of the longest palindrome
// centered at original index 'cen'
int getLongest(int cen, int odd) {
int pos = 2 * cen + 2 + !odd;
return p[pos];
}
// checks whether the substring
// s[l..r] is a palindrome
bool check(int l, int r) {
int res = getLongest((r + l) / 2, (r - l + 1) % 2);
return (r - l + 1) <= res;
}
};
// finds and returns the longest palindromic substring in s
string getLongestPal(string &s) {
int n = s.size(), maxLen = 1, start = 0;
manacher M(s);
for (int i = 0; i < n; ++i) {
int oddLen = M.getLongest(i, 1);
if (oddLen > maxLen) {
// update start for odd-length palindrome
start = i - (oddLen - 1) / 2;
}
int evenLen = M.getLongest(i, 0);
if (evenLen > maxLen) {
// update start for even-length palindrome
start = i - (evenLen - 1) / 2;
}
maxLen = max(maxLen, max(oddLen, evenLen));
}
return s.substr(start, maxLen);
}
int main() {
string s = "forgeeksskeegfor";
cout << getLongestPal(s) << endl;
return 0;
}
Java
class Manacher {
// p[i] stores the radius of the palindrome
// centered at position i in ms
int[] p;
// transformed string with sentinels
// and separators
String ms;
public Manacher(String s) {
// left sentinel to avoid bounds check
StringBuilder sb = new StringBuilder("@");
for (char c : s.toCharArray()) {
// insert '#' between every character
sb.append("#").append(c);
}
// right sentinel
sb.append("#$");
ms = sb.toString();
runManacher();
}
private void runManacher() {
int n = ms.length();
p = new int[n];
int l = 0, r = 0;
for (int i = 1; i < n - 1; ++i) {
int mirror = l + r - i;
if (mirror >= 0 && mirror < n) {
p[i] = Math.max(0, Math.min(r - i, p[mirror]));
} else {
p[i] = 0;
}
// try expanding around center i
while ((i + 1 + p[i]) < n && (i - 1 - p[i]) >= 0 &&
ms.charAt(i + 1 + p[i]) == ms.charAt(i - 1 - p[i])) {
++p[i];
}
// update [l, r] if the new palindrome goes
// beyond current right boundary
if (i + p[i] > r) {
l = i - p[i];
r = i + p[i];
}
}
}
// return the radius of the longest palindrome
// centered at original index 'cen'
public int getLongest(int cen, int odd) {
int pos = 2 * cen + 2 + (odd == 0 ? 1 : 0);
return p[pos];
}
// checks whether the substring
// s[l..r] is a palindrome
public boolean check(int l, int r) {
int res = getLongest((r + l) / 2, (r - l + 1) % 2);
return (r - l + 1) <= res;
}
}
class GfG {
// finds and returns the longest
// palindromic substring in s
public static String getLongestPal(String s) {
int n = s.length(), maxLen = 1, start = 0;
Manacher M = new Manacher(s);
for (int i = 0; i < n; ++i) {
int oddLen = M.getLongest(i, 1);
if (oddLen > maxLen) {
// update start for odd-length palindrome
start = i - (oddLen - 1) / 2;
}
int evenLen = M.getLongest(i, 0);
if (evenLen > maxLen) {
// update start for even-length palindrome
start = i - (evenLen - 1) / 2;
}
maxLen = Math.max(maxLen, Math.max(oddLen, evenLen));
}
return s.substring(start, start + maxLen);
}
public static void main(String[] args) {
String s = "forgeeksskeegfor";
System.out.println(getLongestPal(s));
}
}
Python
class manacher:
# p[i] stores the radius of the palindrome
# centered at position i in ms
def __init__(self, s):
# transformed string with sentinels
# and separators
self.ms = "@"
for c in s:
self.ms += "#" + c
self.ms += "#$"
self.p = [0] * len(self.ms)
self.runManacher()
def runManacher(self):
n = len(self.ms)
l = r = 0
for i in range(1, n - 1):
mirror = l + r - i
if 0 <= mirror < n:
self.p[i] = max(0, min(r - i, self.p[mirror]))
else:
self.p[i] = 0
# try expanding around center i
while (i + 1 + self.p[i] < n and
i - 1 - self.p[i] >= 0 and
self.ms[i + 1 + self.p[i]] == self.ms[i - 1 - self.p[i]]):
self.p[i] += 1
# update [l, r] if the new palindrome goes
# beyond current right boundary
if i + self.p[i] > r:
l = i - self.p[i]
r = i + self.p[i]
# return the radius of the longest palindrome
# centered at original index 'cen'
def getLongest(self, cen, odd):
pos = 2 * cen + 2 + (0 if odd else 1)
return self.p[pos]
# checks whether the substring
# s[l..r] is a palindrome
def check(self, l, r):
length = r - l + 1
return length <= self.getLongest((l + r) // 2, length % 2)
# finds and returns the longest
# palindromic substring in s
def getLongestPal(s):
n = len(s)
maxLen = 1
start = 0
M = manacher(s)
for i in range(n):
oddLen = M.getLongest(i, 1)
if oddLen > maxLen:
# update start for odd-length palindrome
start = i - (oddLen - 1) // 2
evenLen = M.getLongest(i, 0)
if evenLen > maxLen:
# update start for even-length palindrome
start = i - (evenLen - 1) // 2
maxLen = max(maxLen, max(oddLen, evenLen))
return s[start:start + maxLen]
if __name__ == "__main__":
s = "forgeeksskeegfor"
print(getLongestPal(s))
C#
using System;
class manacher {
// p[i] stores the radius of the palindrome
// centered at position i in ms
public int[] p;
// transformed string with sentinels
// and separators
public string ms;
public manacher(string s) {
ms = "@";
foreach (char c in s) {
ms += "#" + c;
}
ms += "#$";
runManacher();
}
void runManacher() {
int n = ms.Length;
p = new int[n];
int l = 0, r = 0;
for (int i = 1; i < n - 1; ++i) {
int mirror = l + r - i;
if (mirror >= 0 && mirror < n)
p[i] = Math.Max(0, Math.Min(r - i, p[mirror]));
else
p[i] = 0;
// try expanding around center i
while ((i + 1 + p[i]) < n && (i - 1 - p[i]) >= 0 &&
ms[i + 1 + p[i]] == ms[i - 1 - p[i]]) {
++p[i];
}
// update [l, r] if the new palindrome goes
// beyond current right boundary
if (i + p[i] > r) {
l = i - p[i];
r = i + p[i];
}
}
}
// return the radius of the longest palindrome
// centered at original index 'cen'
public int getLongest(int cen, int odd) {
int pos = 2 * cen + 2 + (odd == 0 ? 1 : 0);
return p[pos];
}
// checks whether the substring
// s[l..r] is a palindrome
public bool check(int l, int r) {
int res = getLongest((l + r) / 2, (r - l + 1) % 2);
return (r - l + 1) <= res;
}
}
class GfG {
// finds and returns the longest
// palindromic substring in s
public static string getLongestPal(string s) {
int n = s.Length, maxLen = 1, start = 0;
manacher M = new manacher(s);
for (int i = 0; i < n; ++i) {
int oddLen = M.getLongest(i, 1);
if (oddLen > maxLen) {
// update start for odd-length palindrome
start = i - (oddLen - 1) / 2;
}
int evenLen = M.getLongest(i, 0);
if (evenLen > maxLen) {
// update start for even-length palindrome
start = i - (evenLen - 1) / 2;
}
maxLen = Math.Max(maxLen, Math.Max(oddLen, evenLen));
}
return s.Substring(start, maxLen);
}
public static void Main(string[] args) {
string s = "forgeeksskeegfor";
Console.WriteLine(getLongestPal(s));
}
}
JavaScript
class Mancjher {
// p[i] stores the radius of the palindrome
// centered at position i in ms
constructor(s) {
this.ms = "@";
for (let c of s) {
this.ms += "#" + c;
}
this.ms += "#$"; // right sentinel
this.p = new Array(this.ms.length).fill(0);
this.runManacher();
}
runManacher() {
let n = this.ms.length;
let l = 0, r = 0;
for (let i = 1; i < n - 1; ++i) {
let mirror = l + r - i;
if (mirror >= 0 && mirror < n) {
this.p[i] = Math.max(0, Math.min(r - i, this.p[mirror]));
} else {
this.p[i] = 0;
}
// try expanding around center i
while (
(i + 1 + this.p[i]) < n &&
(i - 1 - this.p[i]) >= 0 &&
this.ms[i + 1 + this.p[i]] === this.ms[i - 1 - this.p[i]]
) {
++this.p[i];
}
// update [l, r] if new palindrome goes beyond right
if (i + this.p[i] > r) {
l = i - this.p[i];
r = i + this.p[i];
}
}
}
// return the radius of the longest palindrome
// centered at original index 'cen'
getLongest(cen, odd) {
let pos = 2 * cen + 2 + (odd === 0 ? 1 : 0);
return this.p[pos];
}
// checks whether the substring
// s[l..r] is a palindrome
check(l, r) {
let len = r - l + 1;
return len <= this.getLongest((l + r) >> 1, len % 2);
}
}
// finds and returns the longest
// palindromic substring in s
function getLongestPal(s) {
let n = s.length, maxLen = 1, start = 0;
const M = new Mancjher(s);
for (let i = 0; i < n; ++i) {
let oddLen = M.getLongest(i, 1);
if (oddLen > maxLen) {
start = i - Math.floor((oddLen - 1) / 2);
}
let evenLen = M.getLongest(i, 0);
if (evenLen > maxLen) {
start = i - Math.floor((evenLen - 1) / 2);
}
maxLen = Math.max(maxLen, Math.max(oddLen, evenLen));
}
return s.substring(start, start + maxLen);
}
// Driver Code
const s = "forgeeksskeegfor";
console.log(getLongestPal(s));
Longest Palindromic Substring
Similar Reads
Basics & Prerequisites
Data Structures
Array Data StructureIn this article, we introduce array, implementation in different popular languages, its basic operations and commonly seen problems / interview questions. An array stores items (in case of C/C++ and Java Primitive Arrays) or their references (in case of Python, JS, Java Non-Primitive) at contiguous
3 min read
String in Data StructureA string is a sequence of characters. The following facts make string an interesting data structure.Small set of elements. Unlike normal array, strings typically have smaller set of items. For example, lowercase English alphabet has only 26 characters. ASCII has only 256 characters.Strings are immut
2 min read
Hashing in Data StructureHashing is a technique used in data structures that efficiently stores and retrieves data in a way that allows for quick access. Hashing involves mapping data to a specific index in a hash table (an array of items) using a hash function. It enables fast retrieval of information based on its key. The
2 min read
Linked List Data StructureA linked list is a fundamental data structure in computer science. It mainly allows efficient insertion and deletion operations compared to arrays. Like arrays, it is also used to implement other data structures like stack, queue and deque. Hereâs the comparison of Linked List vs Arrays Linked List:
2 min read
Stack Data StructureA Stack is a linear data structure that follows a particular order in which the operations are performed. The order may be LIFO(Last In First Out) or FILO(First In Last Out). LIFO implies that the element that is inserted last, comes out first and FILO implies that the element that is inserted first
2 min read
Queue Data StructureA Queue Data Structure is a fundamental concept in computer science used for storing and managing data in a specific order. It follows the principle of "First in, First out" (FIFO), where the first element added to the queue is the first one to be removed. It is used as a buffer in computer systems
2 min read
Tree Data StructureTree Data Structure is a non-linear data structure in which a collection of elements known as nodes are connected to each other via edges such that there exists exactly one path between any two nodes. Types of TreeBinary Tree : Every node has at most two childrenTernary Tree : Every node has at most
4 min read
Graph Data StructureGraph Data Structure is a collection of nodes connected by edges. It's used to represent relationships between different entities. If you are looking for topic-wise list of problems on different topics like DFS, BFS, Topological Sort, Shortest Path, etc., please refer to Graph Algorithms. Basics of
3 min read
Trie Data StructureThe Trie data structure is a tree-like structure used for storing a dynamic set of strings. It allows for efficient retrieval and storage of keys, making it highly effective in handling large datasets. Trie supports operations such as insertion, search, deletion of keys, and prefix searches. In this
15+ min read
Algorithms
Searching AlgorithmsSearching algorithms are essential tools in computer science used to locate specific items within a collection of data. In this tutorial, we are mainly going to focus upon searching in an array. When we search an item in an array, there are two most common algorithms used based on the type of input
2 min read
Sorting AlgorithmsA Sorting Algorithm is used to rearrange a given array or list of elements in an order. For example, a given array [10, 20, 5, 2] becomes [2, 5, 10, 20] after sorting in increasing order and becomes [20, 10, 5, 2] after sorting in decreasing order. There exist different sorting algorithms for differ
3 min read
Introduction to RecursionThe process in which a function calls itself directly or indirectly is called recursion and the corresponding function is called a recursive function. A recursive algorithm takes one step toward solution and then recursively call itself to further move. The algorithm stops once we reach the solution
14 min read
Greedy AlgorithmsGreedy algorithms are a class of algorithms that make locally optimal choices at each step with the hope of finding a global optimum solution. At every step of the algorithm, we make a choice that looks the best at the moment. To make the choice, we sometimes sort the array so that we can always get
3 min read
Graph AlgorithmsGraph is a non-linear data structure like tree data structure. The limitation of tree is, it can only represent hierarchical data. For situations where nodes or vertices are randomly connected with each other other, we use Graph. Example situations where we use graph data structure are, a social net
3 min read
Dynamic Programming or DPDynamic Programming is an algorithmic technique with the following properties.It is mainly an optimization over plain recursion. Wherever we see a recursive solution that has repeated calls for the same inputs, we can optimize it using Dynamic Programming. The idea is to simply store the results of
3 min read
Bitwise AlgorithmsBitwise algorithms in Data Structures and Algorithms (DSA) involve manipulating individual bits of binary representations of numbers to perform operations efficiently. These algorithms utilize bitwise operators like AND, OR, XOR, NOT, Left Shift, and Right Shift.BasicsIntroduction to Bitwise Algorit
4 min read
Advanced
Segment TreeSegment Tree is a data structure that allows efficient querying and updating of intervals or segments of an array. It is particularly useful for problems involving range queries, such as finding the sum, minimum, maximum, or any other operation over a specific range of elements in an array. The tree
3 min read
Pattern SearchingPattern searching algorithms are essential tools in computer science and data processing. These algorithms are designed to efficiently find a particular pattern within a larger set of data. Patten SearchingImportant Pattern Searching Algorithms:Naive String Matching : A Simple Algorithm that works i
2 min read
GeometryGeometry is a branch of mathematics that studies the properties, measurements, and relationships of points, lines, angles, surfaces, and solids. From basic lines and angles to complex structures, it helps us understand the world around us.Geometry for Students and BeginnersThis section covers key br
2 min read
Interview Preparation
Practice Problem