NLeetCode Solutions
ProblemsPatternsStatistics
© 2026 Created by Trịnh Minh Nhật
GitHubLeetCode
Related posts
  • 344. Reverse StringEasy
  • 13. Roman to IntegerEasy
  • 14. Longest Common PrefixEasy
  • 20. Valid ParenthesesEasy
  • 26. Remove Duplicates from Sorted ArrayEasy

125. Valid Palindrome

Easy
Two PointersString
Companies:
UberLinkedInFacebookZenefitsMicrosoft
Answered: Mar 28, 2026
View on LeetCode

Problem Description

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*.

Examples

Example 1

Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation:
"amanaplanacanalpanama" is a palindrome.

Example 2

Input: s = "race a car"
Output: false
Explanation:
"raceacar" is not a palindrome.

Example 3

Input: s = " "
Output: true
Explanation:
s is an empty string "" after removing non-alphanumeric characters. Since an empty string reads the same forward and backward, it is a palindrome.

Constraints

  • 1 <= s.length <= 2 * 105
  • s consists only of printable ASCII characters.

Solutions

Complexity Analysis

Time Complexity:O(n)

We iterate through the string once to filter and lowercase it, then Python's reverse slice creates another O(n)O(n)O(n) pass, so the overall time complexity is O(n)O(n)O(n), where n is the length of the input string.

Space Complexity:O(n)

The cleaned string and its reverse each take O(n)O(n)O(n) space proportional to the input length.

This approach first filters out all non-alphanumeric characters and converts the string to lowercase, producing a cleaned version. It then checks whether the cleaned string equals its own reverse using Python's slice notation (s[::-1]). While straightforward and readable, it requires O(n)O(n)O(n) extra space to store the cleaned string and its reverse.

Complexity Analysis

Time Complexity:O(n)

Each character is visited at most once by either pointer, so the total work is O(n)O(n)O(n), where n is the length of the input string.

Space Complexity:O(1)

No auxiliary data structures are used; the two pointer variables require only constant space.

This solution uses two pointers starting at opposite ends of the string and walks them inward. At each step, it skips non-alphanumeric characters using a custom isAlphaNum helper (checking ASCII ranges directly) and then compares the characters case-insensitively. If any mismatch is found, it returns false immediately; if the pointers meet without a mismatch, the string is a palindrome. This avoids creating any auxiliary string, achieving O(1)O(1)O(1) space.

Complexity Analysis

Time Complexity:O(n)

Each character is visited at most once across all pointer movements, giving a linear scan of the input of length n.

Space Complexity:O(1)

Only two pointer variables are maintained; no extra strings or data structures are allocated.

This is the cleanest two-pointer approach: left and right start at the ends of the string, and inner while loops advance each pointer past any non-alphanumeric character using the built-in isalnum() method. The outer loop then compares the characters case-insensitively and moves both pointers inward. The use of nested while loops makes the skipping logic more explicit and avoids the continue-based control flow of Solution 2.

Conclusion

ApproachRatingTime ComplexitySpace ComplexityAdvantagesDisadvantages
Clean and Reverse
O(n)O(n)O(n)O(n)O(n)O(n)Simple and highly readableRequires O(n)O(n)O(n) extra space for the cleaned string and its reverse
Two Pointers with Custom Helper
O(n)O(n)O(n)O(1)O(1)O(1)Avoids built-in methods with explicit ASCII range checksVerbose continue-based control flow reduces readability
Two Pointers
O(n)O(n)O(n)O(1)O(1)O(1)Cleanest O(1)O(1)O(1)-space solution using built-in isalnum()No significant disadvantage

The optimal approach for this problem is Solution 3: Two Pointers, which achieves O(n)O(n)O(n) time complexity and O(1)O(1)O(1) space complexity. It uses nested while loops to skip non-alphanumeric characters with the built-in isalnum() method, resulting in clean, idiomatic code that avoids both auxiliary strings and verbose control flow.


Previous121. Best Time to Buy and Sell Stock
Next136. Single Number
Related posts
  • 344. Reverse StringEasy
  • 13. Roman to IntegerEasy
  • 14. Longest Common PrefixEasy
  • 20. Valid ParenthesesEasy
  • 26. Remove Duplicates from Sorted ArrayEasy
On this page
7 lines
1class Solution:
2 def isPalindrome(self, s: str) -> bool:
3 # Remove non-alphanumeric characters and convert to lowercase
4 s = "".join(c for c in s if c.isalnum()).lower()
5
6 # Check if the cleaned string is equal to its reverse
7 return s == s[::-1]
27 lines
1class Solution:
2 def isPalindrome(self, s: str) -> bool:
3 left, right = 0, len(s) - 1
4
5 while left < right:
6 # Move left pointer to the next alphanumeric character
7 if left < right and not self.isAlphaNum(s[left]):
8 left += 1
9 continue
10
11 # Move right pointer to the previous alphanumeric character
12 if left < right and not self.isAlphaNum(s[right]):
13 right -= 1
14 continue
15
16 # Compare characters at left and right pointers
17 if s[left].lower() != s[right].lower():
18 return False
19
20 left += 1
21 right -= 1
22
23 return True
24
25 # Helper function to check if a character is alphanumeric
26 def isAlphaNum(self, char: str) -> bool:
27 return "a" <= char <= "z" or "A" <= char <= "Z" or "0" <= char <= "9"
20 lines
1class Solution:
2 def isPalindrome(self, s: str) -> bool:
3 left, right = 0, len(s) - 1
4
5 # Use two pointers to compare characters from both ends
6 while left < right:
7 # Skip non-alphanumeric characters
8 while left < right and not s[left].isalnum():
9 left += 1
10 while left < right and not s[right].isalnum():
11 right -= 1
12
13 # Compare characters in a case-insensitive manner
14 if s[left].lower() != s[right].lower():
15 return False
16
17 left += 1
18 right -= 1
19
20 return True