The second, more optimal solution uses a two-pointer technique to check the string in-place, which avoids using extra memory (O(1) space complexity).
Initialize Left and Right Pointers.
Set a left pointer to the start of the string and a right pointer to the end.
l, r = 0, len(s) - 1Iterate Until Pointers Meet. The main loop continues as long as the left pointer is less than the right pointer.
while l < r:
# ...Skip Non-Alphanumeric Characters. From both ends, advance the pointers inward until they each point to an alphanumeric character.
while l < r and not self.alphaNum(s[l]):
l += 1
while r > l and not self.alphaNum(s[r]):
r -= 1Compare Characters.
If the lowercase versions of the characters at the l and r pointers do not match, the string is not a palindrome, and we can return False.
if s[l].lower() != s[r].lower():
return FalseMove Pointers and Continue. If the characters match, move both pointers inward to continue checking the rest of the string.
l, r = l + 1, r - 1Here is the complete and optimal solution using the two-pointer approach.
class Solution:
def isPalindrome(self, s: str) -> bool:
l, r = 0, len(s) - 1
while l < r:
while l < r and not self.alphaNum(s[l]):
l += 1
while r > l and not self.alphaNum(s[r]):
r -= 1
if s[l].lower() != s[r].lower():
return False
l, r = l + 1, r - 1
return True
def alphaNum(self, c):
return (ord('A') <= ord(c) <= ord('Z') or
ord('a') <= ord(c) <= ord('z') or
ord('0') <= ord(c) <= ord('9'))