2Brute2Best
πŸ”₯0

Valid Palindrome

EasyΒ·LeetCode #125Basic Anchor
LeetCode
30-Second Mental ModelTwo Pointers (opposite ends)
Complexity:O(N)β†’O(N)
Key Insight

Put left at the start and right at the end. If either one is on a character that doesn't count, move it inward. Otherwise compare the two characters (ignoring case). If they differ, the answer is false. If they match, move both inward. When they meet, every pair has matched, so the answer is true.

Core Validity Invariant

The string is a palindrome only if every mirrored pair of real characters matches (ignoring case). So one mismatch anywhere means false, and running out of pairs means true.

01

Problem

You are given a string s.

First, imagine cleaning it: turn every uppercase letter into lowercase, and throw away everything that is not a letter or a digit (spaces, commas, colons, and so on).

Return true if the cleaned string reads the same forwards and backwards (a palindrome), and false otherwise.

Input

A string s made of printable ASCII characters.

Output

true if s is a palindrome after cleaning, otherwise false.

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

After cleaning it becomes "amanaplanacanalpanama", which reads the same both ways.

Example 2
Input: s = "race a car"
Output: false

After cleaning it becomes "raceacar". Backwards that is "racaecar" β€” different.

Example 3
Input: s = " "
Output: true

After cleaning, nothing is left. An empty string reads the same both ways.

Constraints
  • β€’ 1 ≀ s.length ≀ 2 Β· 10^5
  • β€’ s contains only printable ASCII characters.
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck β€” each hint is counted.

  1. 1.

    What does "reads the same backwards" mean in terms of positions? Which character must match the first one?

  2. 2.

    Do I really need to build the cleaned string, or can I just ignore the extra characters while reading?

  3. 3.

    If I find one pair of characters that don't match, do I need to look at the rest?

  4. 4.

    After I check the outermost pair, what problem is left?

  5. 5.

    What should happen with a string that has no letters or digits at all?

03

Brute force approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceBuild the cleaned string and its reverse, then compare themO(N)O(N)
OptimalCompare mirrored characters in place, skipping non-alphanumericsO(N)O(1)
09

Why does this belong to this pattern?

Clues in the problem statement
  • β€œreads the same forwards and backwards”Position i must match its mirror position β†’ compare from both ends at once.
  • β€œignore non-alphanumeric characters”Each pointer may need to skip forward on its own before a comparison.
  • β€œreturn true / false”One mismatch ends it early. No need to build anything.
Symmetric structure+compare mirrored positions+skip what doesn't count→Two Pointers (opposite ends)

This is the anchor of the opposite-ends family: start at both ends, look at the pair, decide, move inward. Here the decision is the simplest possible β€” the two sides must simply be equal, and a match moves both pointers at once. The next questions keep the same "two ends move toward each other" shape but change the decision: in Two Sum II only one side moves, chosen by whether the sum is too big or too small.

10

Don't make this mistake

Pattern confusion: treating it as a sliding window

Both pointers here start at opposite ends and walk toward each other. There is no window that grows and shrinks, and nothing between the pointers is being summed or counted. If you write for (right = 0; ...) with left chasing it, you are comparing neighbours, not mirror partners. Palindrome = mirrored pairs = opposite ends.

Forgetting to ignore case
βœ— if (s[left] != s[right]) return false;
βœ“ if (tolower(s[left]) != tolower(s[right])) return false;

"Aa" is a palindrome. Without tolower, 'A' and 'a' look different.

Skipping with a nested while that runs past the other pointer
βœ— while (!isalnum(s[left])) left++;
βœ“ while (left < right && !isalnum(s[left])) left++;

For a string like ".," the inner loop keeps going past right (and even past the end of the string). Always keep the left < right check, or use the if / else-if form shown in the solution.

Thinking digits don't count

The rule is letters and digits. "0P" is not a palindrome: '0' and 'p' are both real characters and they differ. Use isalnum, not isalpha.

11

Want to implement this?

Write it yourself on LeetCode, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like Two Pointers translate into production architectures and low-level memory mechanics.