Valid Palindrome
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.
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.
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.
A string s made of printable ASCII characters.
true if s is a palindrome after cleaning, otherwise false.
After cleaning it becomes "amanaplanacanalpanama", which reads the same both ways.
After cleaning it becomes "raceacar". Backwards that is "racaecar" β different.
After cleaning, nothing is left. An empty string reads the same both ways.
- β’ 1 β€ s.length β€ 2 Β· 10^5
- β’ s contains only printable ASCII characters.
First, think yourself
Before opening any solution, try to answer these on paper. Use hints only when stuck β each hint is counted.
- 1.
What does "reads the same backwards" mean in terms of positions? Which character must match the first one?
- 2.
Do I really need to build the cleaned string, or can I just ignore the extra characters while reading?
- 3.
If I find one pair of characters that don't match, do I need to look at the rest?
- 4.
After I check the outermost pair, what problem is left?
- 5.
What should happen with a string that has no letters or digits at all?
Brute force approach
Optimized approach
Why does this algorithm work?
Dry run
All approaches compared
| Approach | Idea | Time | Space |
|---|---|---|---|
| Brute Force | Build the cleaned string and its reverse, then compare them | O(N) | O(N) |
| Optimal | Compare mirrored characters in place, skipping non-alphanumerics | O(N) | O(1) |
Why does this belong to this pattern?
- β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.
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.
Don't make this mistake
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.
"Aa" is a palindrome. Without tolower, 'A' and 'a' look different.
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.
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.
Want to implement this?
Write it yourself on LeetCode, then come back and compare your code with the solutions above.
Open coding workspaceHow this concept connects to System Design & C++ Systems
Top engineering interviews test whether you understand how algorithms like Two Pointers translate into production architectures and low-level memory mechanics.
Circular Buffer & Ring Queue
Two pointer read/write head synchronization in production memory pools.
Pointers vs References Deep Dive
Pointer arithmetic, dereferencing semantics, and memory layout behind in-place array passes.
const Correctness & East-Const
Passing read-only spans with const int* without copying buffers.