AlgoMaster Logo

Valid Palindrome

Last Updated: March 20, 2026

easy
3 min read

Understanding the Problem

This isn't a straightforward "is this string a palindrome?" check. There are two preprocessing steps baked into the problem: ignore case and ignore non-alphanumeric characters. The string "A man, a plan, a canal: Panama" has spaces, commas, and a colon, but once you strip all of that away and lowercase everything, you get "amanaplanacanalpanama", which reads the same forwards and backwards.

The key question is: do you actually need to build that cleaned-up string, or can you skip over the junk characters on the fly? That distinction is exactly what separates the two approaches below.

Key Constraints:

  • 1 <= s.length <= 2 * 10^5 → With up to 200,000 characters, we need O(n) or better. Both approaches run in O(n) time, but they differ in space usage.
  • s consists only of printable ASCII characters → We need to handle letters, digits, spaces, punctuation, and symbols. No Unicode edge cases to worry about.

Approach 1: Filter and Reverse

Intuition

The most straightforward approach is to do exactly what the problem says: strip out everything that isn't a letter or digit, convert to lowercase, and then check if the result is a palindrome.

How do you check if a string is a palindrome? Reverse it and see if it matches the original. If the cleaned string equals its reverse, we have a palindrome.

Algorithm

  1. Iterate through every character in the input string.
  2. Keep only alphanumeric characters, converting each to lowercase.
  3. Build a new "cleaned" string from these characters.
  4. Reverse the cleaned string.
  5. Compare the cleaned string with its reverse. If they match, return true.

Example Walkthrough

1Input: s = "race a car". Build cleaned string by keeping only alphanumeric chars (lowercased)
0
r
1
a
2
c
3
e
4
5
a
6
7
c
8
a
9
r
1/4

Code

This approach works but allocates extra strings. What if we compared characters directly from both ends of the original string, skipping non-alphanumeric characters as we go?

Approach 2: Two Pointers (Optimal)

Intuition

Instead of building a cleaned string, we can work directly on the original. Place one pointer at the start and one at the end. Move them toward each other, but skip over any character that isn't alphanumeric. When both pointers land on valid characters, compare them case-insensitively. If they ever mismatch, it's not a palindrome. If the pointers cross without a mismatch, it is.

This avoids allocating any extra strings. We're doing the filtering and comparison in a single pass.

Algorithm

  1. Set left to 0 and right to the last index of the string.
  2. While left < right:
    • Move left forward while it points to a non-alphanumeric character.
    • Move right backward while it points to a non-alphanumeric character.
    • If left >= right, break (all valid characters have been compared).
    • Compare the lowercase versions of s[left] and s[right].
    • If they don't match, return false.
    • Move left forward and right backward.
  3. Return true.

Example Walkthrough

1Initialize: left=0, right=29
0
left
A
1
2
m
3
a
4
n
5
,
6
7
a
8
9
p
10
l
11
a
12
n
13
,
14
15
a
16
17
c
18
a
19
n
20
a
21
l
22
:
23
24
P
25
a
26
n
27
a
28
m
29
right
a
1/8

Code