LeetCopilot Logo
LeetCopilot
LeetCode Pattern/Two Pointers/Valid Palindrome Edge Cases: Empty Strings, Single Characters, and Non-Alphanumeric

Valid Palindrome Edge Cases: Empty Strings, Single Characters, and Non-Alphanumeric

LeetCopilot Team
Dec 9, 2025
10 min read
Two PointersPalindromeEdge CasesString ManipulationInterview Prep
Your Valid Palindrome solution works on simple inputs but fails edge cases. Learn comprehensive edge case handling for empty strings, single characters, spaces, and special characters.

You've solved Valid Palindrome. Your solution works on "racecar" and "A man, a plan, a canal: Panama." You submit.

Wrong Answer.

Test case: "" (empty string)

Expected: true
Your output: Crash or false

Or test case: " " (single space)

Expected: true
Your output: false

Or test case: ".," (only punctuation)

Expected: true
Your output: false

Edge cases are the silent killers of palindrome solutions. The core logic is simple, but handling empty strings, single characters, spaces, and non-alphanumeric characters correctly is where most solutions fail.

This guide will teach you comprehensive edge case handling for Valid Palindrome, the exact checks you need, and how to write a bulletproof solution.

TL;DR

Edge cases to handle:

  1. Empty string → true
  2. Single character → true
  3. Only spaces/punctuation → true (after cleaning)
  4. Mixed case → Convert to lowercase
  5. Non-alphanumeric → Filter out

Key insight: Clean the string first (remove non-alphanumeric, convert to lowercase), then check if it's a palindrome.

The Problem: What Makes a Valid Palindrome?

Definition

A string is a palindrome if it reads the same forward and backward, ignoring:

  • Case (uppercase vs lowercase)
  • Non-alphanumeric characters (spaces, punctuation, etc.)

Examples

Valid palindromes:

  • "A man, a plan, a canal: Panama""amanaplanacanalpanama" (palindrome ✓)
  • "race a car""raceacar" (not palindrome ✗)
  • """" (empty, palindrome ✓)
  • " """ (only space, palindrome ✓)
  • "a""a" (single char, palindrome ✓)

Edge Case 1: Empty String

The Test Case

python
s = ""

Expected: true

Why? An empty string reads the same forward and backward (vacuously true).

Common Mistake

python
def isPalindrome(s):
    # Doesn't handle empty string
    left, right = 0, len(s) - 1  # right = -1 for empty string!
    while left < right:
        # ...

Problem: When s = "", right = -1, which is a valid index in Python (wraps around), causing unexpected behavior.

Correct Handling

python
def isPalindrome(s):
    # Clean the string first
    cleaned = ''.join(c.lower() for c in s if c.isalnum())
    
    # Empty string is a palindrome
    if len(cleaned) == 0:
        return True
    
    # Or just proceed with two pointers (handles empty automatically)
    left, right = 0, len(cleaned) - 1
    while left < right:
        if cleaned[left] != cleaned[right]:
            return False
        left += 1
        right -= 1
    return True

Better: The loop condition left < right handles empty strings automatically (loop doesn't run).

Edge Case 2: Single Character

The Test Case

python
s = "a"
s = "A"
s = "1"

Expected: true

Why? A single character is always a palindrome.

Common Mistake

python
# Doesn't explicitly handle single character
# But usually works if loop condition is correct

Correct Handling

python
# After cleaning
if len(cleaned) <= 1:
    return True

# Or let the loop handle it (left >= right immediately)

Best practice: Explicit check for len <= 1 makes intent clear.

Edge Case 3: Only Spaces and Punctuation

The Test Cases

python
s = " "
s = ".,!?"
s = "   "
s = "!!!"

Expected: true (all become empty string after cleaning)

Why? After removing non-alphanumeric characters, the string is empty, which is a palindrome.

Common Mistake

python
def isPalindrome(s):
    # Doesn't clean the string
    left, right = 0, len(s) - 1
    while left < right:
        if s[left] != s[right]:  # Compares spaces/punctuation!
            return False
        left += 1
        right -= 1
    return True

Problem: Compares non-alphanumeric characters, which shouldn't be considered.

Correct Handling

python
# Clean the string first
cleaned = ''.join(c.lower() for c in s if c.isalnum())

# Now check if cleaned string is a palindrome

Edge Case 4: Mixed Case

The Test Cases

python
s = "A"
s = "Aa"
s = "RaceCar"

Expected: true (case-insensitive)

Why? The problem ignores case differences.

Common Mistake

python
# Doesn't convert to lowercase
if s[left] != s[right]:  # 'A' != 'a' → False!
    return False

Correct Handling

python
# Convert to lowercase during cleaning
cleaned = ''.join(c.lower() for c in s if c.isalnum())

Edge Case 5: Non-Alphanumeric Characters

The Test Cases

python
s = "A man, a plan, a canal: Panama"
s = "race a car"
s = "0P"

Expected:

  • "A man, a plan, a canal: Panama"true
  • "race a car"false
  • "0P"false

Common Mistake

python
# Doesn't filter non-alphanumeric
# Compares spaces, commas, colons, etc.

Correct Handling

python
# Filter out non-alphanumeric during cleaning
cleaned = ''.join(c.lower() for c in s if c.isalnum())

The Complete, Bulletproof Solution

Approach 1: Clean First, Then Check

python
def isPalindrome(s: str) -> bool:
    # Step 1: Clean the string
    # - Convert to lowercase
    # - Keep only alphanumeric characters
    cleaned = ''.join(c.lower() for c in s if c.isalnum())
    
    # Step 2: Check if cleaned string is a palindrome
    left, right = 0, len(cleaned) - 1
    
    while left < right:
        if cleaned[left] != cleaned[right]:
            return False
        left += 1
        right -= 1
    
    return True

Why this works:

  • ✅ Handles empty string (loop doesn't run)
  • ✅ Handles single character (loop doesn't run)
  • ✅ Handles only spaces/punctuation (becomes empty after cleaning)
  • ✅ Handles mixed case (converted to lowercase)
  • ✅ Handles non-alphanumeric (filtered out)

Approach 2: Skip Non-Alphanumeric On-the-Fly

python
def isPalindrome(s: str) -> bool:
    left, right = 0, len(s) - 1
    
    while left < right:
        # Skip non-alphanumeric from left
        while left < right and not s[left].isalnum():
            left += 1
        
        # Skip non-alphanumeric from right
        while left < right and not s[right].isalnum():
            right -= 1
        
        # Compare (case-insensitive)
        if s[left].lower() != s[right].lower():
            return False
        
        left += 1
        right -= 1
    
    return True

Why this works:

  • ✅ Doesn't create a new string (O(1) space)
  • ✅ Skips non-alphanumeric characters
  • ✅ Handles all edge cases

Trade-off: More complex logic, but O(1) space instead of O(n).

JavaScript Implementation

javascript
function isPalindrome(s) {
    // Clean the string
    const cleaned = s
        .toLowerCase()
        .split('')
        .filter(c => /[a-z0-9]/.test(c))
        .join('');
    
    // Check palindrome
    let left = 0, right = cleaned.length - 1;
    
    while (left < right) {
        if (cleaned[left] !== cleaned[right]) {
            return false;
        }
        left++;
        right--;
    }
    
    return true;
}

Java Implementation

java
public boolean isPalindrome(String s) {
    int left = 0, right = s.length() - 1;
    
    while (left < right) {
        // Skip non-alphanumeric from left
        while (left < right && !Character.isLetterOrDigit(s.charAt(left))) {
            left++;
        }
        
        // Skip non-alphanumeric from right
        while (left < right && !Character.isLetterOrDigit(s.charAt(right))) {
            right--;
        }
        
        // Compare (case-insensitive)
        if (Character.toLowerCase(s.charAt(left)) != 
            Character.toLowerCase(s.charAt(right))) {
            return false;
        }
        
        left++;
        right--;
    }
    
    return true;
}

Edge Case Test Suite

Test your solution with these cases:

python
test_cases = [
    # Edge case: empty string
    ("", True),
    
    # Edge case: single character
    ("a", True),
    ("A", True),
    ("1", True),
    
    # Edge case: only spaces
    (" ", True),
    ("   ", True),
    
    # Edge case: only punctuation
    (".,!?", True),
    ("!!!", True),
    
    # Edge case: mixed case
    ("Aa", True),
    ("RaceCar", True),
    
    # Normal cases
    ("A man, a plan, a canal: Panama", True),
    ("race a car", False),
    ("racecar", True),
    ("hello", False),
    
    # Edge case: numbers
    ("0P", False),
    ("121", True),
    
    # Edge case: two characters
    ("ab", False),
    ("aa", True),
]

for s, expected in test_cases:
    result = isPalindrome(s)
    status = "✓" if result == expected else "✗"
    print(f"{status} isPalindrome('{s}') = {result} (expected {expected})")

Common Mistakes Summary

MistakeProblemFix
Not cleaning stringCompares non-alphanumericFilter with isalnum()
Not converting case'A' != 'a'Use .lower()
Not handling emptyIndex -1 or crashCheck len <= 1 or rely on loop
Not handling spacesCompares spacesFilter during cleaning
Wrong loop conditionProcesses middle twiceUse left < right, not <=

Time and Space Complexity

Approach 1 (Clean first):

  • Time: O(n) - one pass to clean, one pass to check
  • Space: O(n) - new cleaned string

Approach 2 (Skip on-the-fly):

  • Time: O(n) - one pass with skipping
  • Space: O(1) - no new string

Practice Strategy

To master palindrome edge cases:

  1. Solve Valid Palindrome (#125) - basic version
  2. Solve Valid Palindrome II (#680) - allow one deletion
  3. Test with all edge cases from this guide
  4. Write your own test suite before submitting
  5. Compare both approaches (clean first vs skip on-the-fly)

FAQ

Q: Is an empty string a palindrome?

A: Yes. It reads the same forward and backward (vacuously true).

Q: What about a string with only spaces?

A: After removing non-alphanumeric characters, it becomes empty, which is a palindrome.

Q: Should I use the O(1) space approach?

A: If the problem requires O(1) space, yes. Otherwise, cleaning first is simpler and more readable.

Q: How do I handle Unicode characters?

A: Use isalnum() which handles Unicode. For ASCII-only, you can use regex [a-zA-Z0-9].

Q: What if the problem allows one character deletion?

A: That's Valid Palindrome II (#680). You need a helper function to check if a substring is a palindrome after skipping one character.

Conclusion

Valid Palindrome is simple in concept but tricky in edge cases. The key is comprehensive cleaning and correct loop conditions.

Edge cases to handle:

  1. ✅ Empty string
  2. ✅ Single character
  3. ✅ Only spaces/punctuation
  4. ✅ Mixed case
  5. ✅ Non-alphanumeric characters

The bulletproof pattern:

python
# Clean the string
cleaned = ''.join(c.lower() for c in s if c.isalnum())

# Check palindrome
left, right = 0, len(cleaned) - 1
while left < right:
    if cleaned[left] != cleaned[right]:
        return False
    left += 1
    right -= 1
return True

Why it works:

  • Handles all edge cases automatically
  • Clean, readable code
  • Easy to test and debug

Master these edge cases, and you'll never fail a palindrome problem again. For more on two pointers, see the complete guide and opposite direction template.

Next time you see a palindrome problem, remember: clean first, then check.

Want to Practice LeetCode Smarter?

LeetCopilot is a free browser extension that enhances your LeetCode practice with AI-powered hints, personalized study notes, and realistic mock interviews — all designed to accelerate your coding interview preparation.

Also compatible with Edge, Brave, and Opera

Related Tutorials