Skip to main content

125. Valid Palindrome

easyAsked at Meta

Given a string, return true if it's a palindrome after lowercasing and ignoring non-alphanumeric characters. Meta asks this to test whether you reach for the two-pointer in-place approach instead of building a cleaned copy of the string.

By Alex Chen, Founder, InterviewChamp.AI · Last verified

Source citations

Public interview reports confirming this problem appears in Meta loops.

  • Glassdoor (2026-Q1)Meta E3/E4 phone-screen warm-up; classic intro.
  • Blind (2025-11)Recurring Meta new-grad onsite question.

Problem

A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Given a string s, return true if it is a palindrome, or false otherwise.

Constraints

  • 1 <= s.length <= 2 * 10^5
  • s consists only of printable ASCII characters.

Examples

Example 1

Input
s = "A man, a plan, a canal: Panama"
Output
true

Explanation: "amanaplanacanalpanama" is a palindrome.

Example 2

Input
s = "race a car"
Output
false

Example 3

Input
s = " "
Output
true

Explanation: After removing non-alphanumeric chars, the string is empty, which reads the same forward and backward.

Approaches

1. Build cleaned copy + reverse compare

Filter+lowercase the string into a new string. Compare with its reverse.

Time
O(n)
Space
O(n)
function isPalindromeClean(s) {
  const clean = s.toLowerCase().replace(/[^a-z0-9]/g, '');
  return clean === clean.split('').reverse().join('');
}

Tradeoff: Easy to write and obviously correct. The O(n) extra space is fine for typical inputs but misses the elegance of two-pointer.

2. Two-pointer in place (optimal)

Pointers from both ends. Skip non-alphanumeric on each side. Compare lowercased chars.

Time
O(n)
Space
O(1)
function isPalindrome(s) {
  function isAlnum(c) {
    return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9');
  }
  let l = 0, r = s.length - 1;
  while (l < r) {
    while (l < r && !isAlnum(s[l])) l++;
    while (l < r && !isAlnum(s[r])) r--;
    if (s[l].toLowerCase() !== s[r].toLowerCase()) return false;
    l++;
    r--;
  }
  return true;
}

Tradeoff: O(1) extra space, single pass with two pointers. The inner skip loops handle non-alphanumeric without allocating a cleaned copy.

Meta-specific tips

Meta interviewers expect the O(1) space version. The two-pointer pattern is foundational at Meta — if you reach for the regex-cleanup approach without acknowledging the space tradeoff, you'll get the easy version but lose the 'higher bar' signal. Mention both, then code the two-pointer.

Common mistakes

  • Forgetting to lowercase before comparing.
  • Including spaces or punctuation in the comparison.
  • Off-by-one on the while loop condition (l < r vs l <= r — l < r is correct because at l == r there's nothing to compare).

Follow-up questions

An interviewer at Meta may pivot to one of these next:

  • Valid Palindrome II (LC 680): allow one deletion.
  • What if 'palindrome' meant 'palindrome ignoring case AND whitespace AND punctuation' (already covered) — what about unicode?
  • Longest palindromic subsequence (different problem class — DP).

Solve it now

Free. No sign-up. Python and JavaScript run instantly in your browser.

Output

Press Run or Cmd+Enter to execute

FAQ

Why two-pointer when the regex version is simpler?

Same asymptotic time but O(1) space vs O(n). For huge strings, that matters. Meta interviewers specifically value the in-place approach as a signal of low-level fluency.

Is toLowerCase per-char inefficient?

It's O(1) per call — JavaScript's toLowerCase on a 1-char string is constant time. Same for char-class checks.

Practice these live with InterviewChamp.AI

Drill Valid Palindrome and other Meta interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.

Practice these live with InterviewChamp.AI →