Longest Palindromic Substring

Last Updated : 7 Oct, 2026

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.

Try It Yourself
redirect icon

[Naive Approach] Generating all Substrings - 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));

Output
geeksskeeg

[Better Approach - 1] 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));

Output
geeksskeeg

[Better Approach - 2] 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));

Output
geeksskeeg

[Expected Approach] 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 <string>
#include <vector>
using namespace std;

string getLongestPal(string &s)
{
    if (s.empty())
        return "";

    // Transform the string using separators
    // and sentinels.
    string ms = "@";

    for (char c : s)
    {
        ms += "#" + string(1, c);
    }

    ms += "#$";

    int m = ms.size();
    vector<int> p(m, 0);

    int l = 0, r = 0;

    // Manacher's algorithm
    for (int i = 1; i < m - 1; ++i)
    {

        // Use the mirror position
        if (i < r)
        {
            int mirror = l + r - i;
            p[i] = min(r - i, p[mirror]);
        }

        // Expand around the current center
        while (ms[i + 1 + p[i]] == ms[i - 1 - p[i]])
        {
            ++p[i];
        }

        // Update the current palindrome range
        if (i + p[i] > r)
        {
            l = i - p[i];
            r = i + p[i];
        }
    }

    int maxLen = 1;
    int start = 0;

    // Find the longest palindrome
    for (int i = 1; i < m - 1; ++i)
    {
        if (p[i] > maxLen)
        {
            maxLen = p[i];
            start = (i - p[i]) / 2;
        }
    }

    return s.substr(start, maxLen);
}

int main()
{
    string s = "forgeeksskeegfor";
    cout << getLongestPal(s) << endl;

    return 0;
}
Java
import java.util.Arrays;

public class GFG {
    public static String getLongestPal(String s)
    {
        if (s.isEmpty())
            return "";

        // Transform the string using separators
        // and sentinels.
        StringBuilder ms = new StringBuilder("@");

        for (char c : s.toCharArray()) {
            ms.append("#").append(c);
        }

        ms.append("#$");

        int m = ms.length();
        int[] p = new int[m];

        int l = 0, r = 0;

        // Manacher's algorithm
        for (int i = 1; i < m - 1; ++i) {

            // Use the mirror position
            if (i < r) {
                int mirror = l + r - i;
                p[i] = Math.min(r - i, p[mirror]);
            }

            // Expand around the current center
            while (ms.charAt(i + 1 + p[i])
                   == ms.charAt(i - 1 - p[i])) {
                ++p[i];
            }

            // Update the current palindrome range
            if (i + p[i] > r) {
                l = i - p[i];
                r = i + p[i];
            }
        }

        int maxLen = 1;
        int start = 0;

        // Find the longest palindrome
        for (int i = 1; i < m - 1; ++i) {
            if (p[i] > maxLen) {
                maxLen = p[i];
                start = (i - p[i]) / 2;
            }
        }

        return s.substring(start, start + maxLen);
    }

    public static void main(String[] args)
    {
        String s = "forgeeksskeegfor";
        System.out.println(getLongestPal(s));
    }
}
Python
def getLongestPal(s):
    if not s:
        return ""

    # Transform the string using separators
    # and sentinels.
    ms = "@"

    for c in s:
        ms += "#" + c

    ms += "#$"

    m = len(ms)
    p = [0] * m

    l, r = 0, 0

    # Manacher's algorithm
    for i in range(1, m - 1):

        # Use the mirror position
        if i < r:
            mirror = l + r - i
            p[i] = min(r - i, p[mirror])

        # Expand around the current center
        while i - 1 - p[i] >= 0 and i + 1 + p[i] < m and ms[i - 1 - p[i]] == ms[i + 1 + p[i]]:
            p[i] += 1

        # Update the current palindrome range
        if i + p[i] > r:
            l = i - p[i]
            r = i + p[i]

    maxLen = 1
    start = 0

    # Find the longest palindrome
    for i in range(1, m - 1):
        if p[i] > maxLen:
            maxLen = p[i]
            start = (i - p[i]) // 2

    return s[start:start + maxLen]


if __name__ == '__main__':
    s = "forgeeksskeegfor"
    print(getLongestPal(s))
C#
using System;

class GFG {
    static string getLongestPal(string s)
    {
        if (string.IsNullOrEmpty(s))
            return "";

        // Transform the string using separators
        // and sentinels.
        string ms = "@";

        foreach(char c in s) { ms += "#" + c; }

        ms += "#$";

        int m = ms.Length;
        int[] p = new int[m];

        int l = 0, r = 0;

        // Manacher's algorithm
        for (int i = 1; i < m - 1; ++i) {
            // Use the mirror position
            if (i < r) {
                int mirror = l + r - i;
                p[i] = Math.Min(r - i, p[mirror]);
            }

            // Expand around the current center
            while (ms[i + 1 + p[i]] == ms[i - 1 - p[i]]) {
                ++p[i];
            }

            // Update the current palindrome range
            if (i + p[i] > r) {
                l = i - p[i];
                r = i + p[i];
            }
        }

        int maxLen = 1;
        int start = 0;

        // Find the longest palindrome
        for (int i = 1; i < m - 1; ++i) {
            if (p[i] > maxLen) {
                maxLen = p[i];
                start = (i - p[i]) / 2;
            }
        }

        return s.Substring(start, maxLen);
    }

    static void Main()
    {
        string s = "forgeeksskeegfor";
        Console.WriteLine(getLongestPal(s));
    }
}
JavaScript
function getLongestPal(s)
{
    if (s.length === 0)
        return "";

    // Transform the string using separators
    // and sentinels.
    let ms = "@";

    for (let c of s) {
        ms += "#" + c;
    }

    ms += "#$";

    let m = ms.length;
    let p = new Array(m).fill(0);

    let l = 0, r = 0;

    // Manacher's algorithm
    for (let i = 1; i < m - 1; ++i) {

        // Use the mirror position
        if (i < r) {
            let mirror = l + r - i;
            p[i] = Math.min(r - i, p[mirror]);
        }

        // Expand around the current center
        while (ms[i + 1 + p[i]] === ms[i - 1 - p[i]]) {
            ++p[i];
        }

        // Update the current palindrome range
        if (i + p[i] > r) {
            l = i - p[i];
            r = i + p[i];
        }
    }

    let maxLen = 1;
    let start = 0;

    // Find the longest palindrome
    for (let i = 1; i < m - 1; ++i) {
        if (p[i] > maxLen) {
            maxLen = p[i];
            start = (i - p[i]) / 2;
        }
    }

    return s.substring(start, start + maxLen);
}

// Driver Code
console.log(getLongestPal("forgeeksskeegfor"));

Output
geeksskeeg
Comment