Two-Pointer Approach (Optimal)

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

  1. 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) - 1
  2. Iterate Until Pointers Meet. The main loop continues as long as the left pointer is less than the right pointer.

    while l < r:
        # ...
  3. 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 -= 1
  4. Compare 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 False
  5. Move Pointers and Continue. If the characters match, move both pointers inward to continue checking the rest of the string.

    l, r = l + 1, r - 1

Final Python Code (Two-Pointer Solution)

Here 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'))