Longest Palindromic Substring

Difficulty: Medium

Given a string s, find the longest contiguous substring of s that reads the same forwards and backwards. If there are multiple longest palindromic substrings, returning any one of them is fine.

Examples

Input: s = "babad"
Output: "bab"

"aba" is also a valid answer — both have length 3.

Input: s = "cbbd"
Output: "bb"

The longest palindrome is "bb"; single letters like "c" or "d" are shorter.

Input: s = "a"
Output: "a"

Constraints

  • 1 <= s.length <= 1000

  • s consists of only lowercase English letters

Approach

A palindrome is defined by its center: everything mirrors outward from the middle. That means instead of checking every one of the roughly n²/2 substrings independently, you can pick every possible center — each single character (for odd-length palindromes) and every gap between two characters (for even-length palindromes) — and grow outward from it as far as the mirroring holds.

For each of the 2n - 1 centers, expanding outward stops the moment the two sides stop matching, so the whole scan stays quadratic instead of cubic. Track the longest palindrome seen as you go.

Solutions

Brute Force — Check Every Substring

Generate every possible substring, check whether each one is a palindrome by comparing it to its own reverse, and keep the longest one found.

function longestPalindrome(s) {
  function isPalindrome(str) {
    let left = 0;
    let right = str.length - 1;
    while (left < right) {
      if (str[left] !== str[right]) return false;
      left++;
      right--;
    }
    return true;
  }

  let longest = "";
  for (let i = 0; i < s.length; i++) {
    for (let j = i; j < s.length; j++) {
      const candidate = s.slice(i, j + 1);
      if (candidate.length > longest.length && isPalindrome(candidate)) {
        longest = candidate;
      }
    }
  }
  return longest;
}

Time: O(n^3) — O(n^2) substrings, each checked in O(n) · Space: O(1) extra, ignoring the substrings themselves

Optimal — Expand Around Center

Treat every character (and every gap between two characters) as a potential center of a palindrome, and grow outward from it while both sides keep matching. Track the widest palindrome found across all centers.

function longestPalindrome(s) {
  let start = 0;
  let maxLength = 1;

  function expand(left, right) {
    while (left >= 0 && right < s.length && s[left] === s[right]) {
      left--;
      right++;
    }
    // left/right overshot by one step; the real palindrome is (left+1 .. right-1)
    const length = right - left - 1;
    if (length > maxLength) {
      maxLength = length;
      start = left + 1;
    }
  }

  for (let i = 0; i < s.length; i++) {
    expand(i, i);       // odd-length palindromes centered on i
    expand(i, i + 1);   // even-length palindromes centered between i and i+1
  }

  return s.slice(start, start + maxLength);
}

Time: O(n^2) · Space: O(1) extra