Skip to content

S2Q1 · Check Palindrome (Advanced)

⚡ Quick Reference

Function: is_palindrome(s: str) -> bool

Core idea: keep only alphanumeric characters, lowercase everything, then compare with its reverse.

def is_palindrome(s: str) -> bool:
    cleaned = "".join(c.lower() for c in s if c.isalnum())
    return cleaned == cleaned[::-1]

Key rules: - c.isalnum() keeps letters and digits, discards spaces and punctuation - Lowercase everything with .lower() for case-insensitive comparison - cleaned[::-1] reverses the cleaned string


Problem Statement

Problem

Write a function is_palindrome(s) that returns True if the string is a palindrome when ignoring spaces, punctuation, and capitalisation.

Examples:

Input
"A man, a plan, a canal, Panama!"
Output
True
Input
"racecar"
Output
True
Input
"hello"
Output
False
Input
"No lemon, no melon"
Output
True

Problem statement error

The original problem lists "No lemon, no melon"False. This is incorrect. After cleaning: "nolemonnomelon" which reads the same forwards and backwards → True. The correct answer is True.


Tracing all examples

"A man, a plan, a canal, Panama!"

Keep alphanumeric, lowercase:
"amanaplanacanalpanama"
Reversed: "amanaplanacanalpanama"  → True ✓

"racecar"

Cleaned: "racecar"
Reversed: "racecar"  → True ✓

"hello"

Cleaned: "hello"
Reversed: "olleh"  → False ✓

"No lemon, no melon"

Cleaned: "nolemonnomelon"
Reversed: "nolemonnomelon"  → True ✓


Solution approaches

def is_palindrome(s: str) -> bool:
    cleaned = "".join(c.lower() for c in s if c.isalnum())
    return cleaned == cleaned[::-1]
def is_palindrome(s: str) -> bool:
    cleaned = "".join(c.lower() for c in s if c.isalnum())
    left, right = 0, len(cleaned) - 1
    while left < right:
        if cleaned[left] != cleaned[right]:
            return False
        left  += 1
        right -= 1
    return True

Two-pointer approach - checks from both ends towards the middle. Stops early on the first mismatch. O(n) time, O(1) extra space (after cleaning).

def is_palindrome(s: str) -> bool:
    cleaned = "".join(filter(str.isalnum, s)).lower()
    return cleaned == cleaned[::-1]

filter(str.isalnum, s) removes non-alphanumeric characters. .lower() on the joined string lowercases everything at once.

is_palindrome = lambda s: (
    lambda c: c == c[::-1]
)("".join(x.lower() for x in s if x.isalnum()))

Key takeaways

01

str.isalnum() - keep letters and digits only

c.isalnum() returns True for letters (a-z, A-Z) and digits (0-9), and False for spaces, commas, exclamation marks, and all other punctuation. One method replaces a long list of manual checks.

02

Clean first, then compare - don't skip characters on the fly

Building the cleaned string first and comparing it as a whole is simpler and less error-prone than trying to skip non-alphanumeric characters while doing the two-pointer check simultaneously.

03

[::-1] reverses any sequence

Slice with step -1 reverses strings, lists, and tuples. cleaned == cleaned[::-1] is the cleanest palindrome check in Python - no loop required.