Longest Palindromic Substring

Last Updated : 27 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 whenever we find a longer 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