Skip to main content

17. Valid Palindrome

easyAsked at Vercel

Decide whether a string is a palindrome after normalizing (lowercase + remove non-alphanumeric). Vercel asks this to test string-handling fluency plus the two-pointer in-place sweep — same pattern as their URL-segment normalizer.

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

Source citations

Public interview reports confirming this problem appears in Vercel loops.

  • Glassdoor (2025-Q4)Vercel screen; two-pointer expected over the regex shortcut.
  • LeetCode Discuss (2026-Q1)Mentioned in Vercel onsite recap.

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

Example 2

Input
s = "race a car"
Output
false

Example 3

Input
s = " "
Output
true

Explanation: After cleanup the string is empty, which is a palindrome.

Approaches

1. Clean then reverse-compare

Lowercase, strip non-alphanumeric, then check str === str.reverse().

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

Tradeoff: Works but allocates three intermediate strings. Mention as the obvious starting point, then pivot.

2. Two-pointer with in-place skip (optimal)

Pointers from both ends. Skip non-alphanumerics on each side, then compare lowercased characters.

Time
O(n)
Space
O(1)
function isPalindrome(s) {
  const isAlnum = (c) => /[a-z0-9]/i.test(c);
  let i = 0, j = s.length - 1;
  while (i < j) {
    while (i < j && !isAlnum(s[i])) i++;
    while (i < j && !isAlnum(s[j])) j--;
    if (s[i].toLowerCase() !== s[j].toLowerCase()) return false;
    i++; j--;
  }
  return true;
}

Tradeoff: O(1) extra space. The two inner whiles must check i < j to avoid infinite loops when the string is all-punctuation.

Vercel-specific tips

Vercel grades for the two-pointer with in-place character skipping. Bonus signal: explicitly handling the all-punctuation case (the inner whiles need the i < j guard). Avoid the regex shortcut unless the interviewer allows it — they want the manual skip logic.

Common mistakes

  • Forgetting i < j in the inner whiles — infinite loop on inputs like ',,,'.
  • Using charCodeAt to test alphanumeric and getting the ranges wrong — verify '0'-'9', 'a'-'z', 'A'-'Z' all included.
  • Mutating the string with replace inside the loop — strings are immutable in JS, so every replace allocates.

Follow-up questions

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

  • Allow removing at most one character (LC 680).
  • Find the longest palindromic substring (LC 5).
  • Valid palindrome with custom alphabet (e.g., ignore digits).

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 pointers and not reverse-compare?

Reverse-compare allocates a second string. Two-pointer is O(1) space and exits early on the first mismatch — both wins.

What about Unicode?

ASCII-only by constraint. For Unicode, normalize with String.normalize('NFD') and a Unicode-aware regex; flag the interviewer that this gets significantly harder.

Practice these live with InterviewChamp.AI

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

Practice these live with InterviewChamp.AI →