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.