Skip to content

Valid Palindrome

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. Alphanumeric characters include letters and numbers. Given a string s, return true if it is a palindrome, or false otherwise.

InputOutputReason
"A man, a plan, a canal: Panama"trueCleaned: "amanaplanacanalpanama" is a palindrome
"race a car"falseCleaned: "raceacar" is not a palindrome
" "trueAfter cleaning: "" — empty string is a palindrome
  • 1 <= s.length <= 2 × 10^5
  • s consists only of printable ASCII characters
ApproachTimeSpaceBest When
Two PointersO(n)O(1)Preferred — no extra allocation
Clean Then CheckO(n)O(n)Clarity, simpler code
★ Recommended

Place left at the start and right at the end of the string. Skip non-alphanumeric characters on both sides, then compare the lowercased characters at each pointer. If any mismatch is found, return false. If the pointers meet or cross, return true.

⏱ Time O(n) Single pass 💾 Space O(1) No extra allocation

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

Cleaned view (not actually built): "amanaplanacanalpanama"

Stepleft charright charmatch?action
1'A'a'a'advance both
2m'm'advance both
3a'a'advance both
right pointer skips ':', ' 'left skips ',', ' 'skip non-alphanumeric
lastpointers meetreturn true

Key behavior — skipping non-alphanumeric characters:

When the left pointer lands on ',' or ' ', the inner while loop advances it until it finds an alphanumeric character without doing any comparison. The same happens on the right side.

Animated walkthrough

Two pointers converging on 'A man, a plan, a canal: Panama'

Use Next or Autoplay to watch the left and right pointers skip punctuation and spaces, then compare alphanumeric characters.

Step 1 of 4 Target: All characters matched
Waiting to begin...
Array state
Memory / lookup state

function isPalindrome(s):
left, right = 0, len(s) - 1
while left < right:
while left < right and not isAlphanumeric(s[left]):
left++
while left < right and not isAlphanumeric(s[right]):
right--
if lower(s[left]) != lower(s[right]):
return false
left++; right--
return true
valid_palindrome_two_pointer.py
def is_palindrome(s: str) -> bool:
left, right = 0, len(s) - 1
while left < right:
while left < right and not s[left].isalnum():
left += 1
while left < right and not s[right].isalnum():
right -= 1
if s[left].lower() != s[right].lower():
return False
left += 1
right -= 1
return True
✓ Simple

Filter the string to keep only alphanumeric characters, lowercase them all, then check if the resulting string equals its own reverse. Simple and readable, but allocates O(n) extra space.

⏱ Time O(n) Single pass 💾 Space O(n) Cleaned string storage
function isPalindrome(s):
cleaned = [c.lower() for c in s if c.isalnum()]
return cleaned == reversed(cleaned)
valid_palindrome_clean.py
def is_palindrome(s: str) -> bool:
cleaned = [c.lower() for c in s if c.isalnum()]
return cleaned == cleaned[::-1]
✓ Simple

A third approach demonstrating an alternative technique for solving this problem. This implementation optimizes either time or space complexity compared to the previous approaches.

⏱ Time O(n) Optimized complexity 💾 Space O(1) Efficient space usage
function approach3():
// Implementation approach goes here
valid_palindrome_optimized.py
"""
Solution for Valid Palindrome
"""
def solve():
"""Implementation for approach 3 of Valid Palindrome"""
pass
if __name__ == "__main__":
print("Solution ready")