Introduction
LeetCode 125: Valid Palindrome is a string manipulation problem that requires checking whether a given string is a valid palindrome, considering only alphanumeric characters and ignoring spaces, punctuation, and case sensitivity. This problem can be efficiently solved using the two-pointer technique, which ensures that we traverse the string only once, making the solution both optimal and easy to implement.
A palindrome is a word, phrase, or sequence that reads the same backward as forward, such as "madam", "racecar", or "A man, a plan, a canal, Panama". The problem here asks us to implement a function that checks whether a given string is a palindrome, ignoring non-alphanumeric characters and considering the string case-insensitively.
Problem Statement
Given a string s, return true if it is a valid palindrome (i.e., reads the same forward and backward), and return false otherwise.
Note:
- Only alphanumeric characters (letters and numbers) should be considered.
- The comparison should be case-insensitive.
Example 1:
go
Input: "A man, a plan, a canal: Panama"
Output: true
Explanation: "A man, a plan, a canal: Panama" is a palindrome after removing non-alphanumeric characters and converting to lowercase.
Example 2:
go
Input: "race a car"
Output: false
Explanation: "race a car" is not a palindrome after removing non-alphanumeric characters.
Approach:
Two-Pointer Technique:
The optimal way to solve this problem is using the two-pointer technique. The idea is to use two pointers, one starting at the beginning (left) and the other starting at the end (right) of the string. We then:
- Skip non-alphanumeric characters on both sides.
- Compare the characters at the
left and right pointers.
- If the characters are not equal (case-insensitive), return
false.
- If they are equal, move the pointers inward and repeat the process.
Steps:
- Initialize two pointers: one at the beginning of the string and one at the end.
- While the
left pointer is less than or equal to the right pointer:
- Skip over non-alphanumeric characters.
- Compare the characters at the
left and right pointers, ensuring the comparison is case-insensitive.
- If they differ, return
false.
- If we finish the comparison without finding any mismatches, return
true.
Go Implementation
Solution Using Two Pointers
go
package main
import (
"fmt"
"unicode"
)
// isPalindrome checks if the given string is a valid palindrome.
func isPalindrome(s string) bool {
left, right := 0, len(s)-1
for left < right {
// Skip non-alphanumeric characters on the left side
for left < right && !unicode.IsAlnum(rune(s[left])) {
left++
}
// Skip non-alphanumeric characters on the right side
for left < right && !unicode.IsAlnum(rune(s[right])) {
right--
}
// Compare the characters at left and right, case-insensitive
if unicode.ToLower(rune(s[left])) != unicode.ToLower(rune(s[right])) {
return false
}
left++
right--
}
return true
}
func main() {
// Test the isPalindrome function with some examples.
fmt.Println(isPalindrome("A man, a plan, a canal: Panama")) // Output: true
fmt.Println(isPalindrome("race a car")) // Output: false
fmt.Println(isPalindrome(" ")) // Output: true
fmt.Println(isPalindrome("No 'x' in Nixon")) // Output: true
}
Explanation:
- Unicode Package:
- We use the
unicode.IsAlnum() function to check if a character is alphanumeric (i.e., a letter or digit).
- We use
unicode.ToLower() to convert the characters to lowercase to ensure the comparison is case-insensitive.
- Two-Pointer Approach:
- The pointers
left and right are initialized at the beginning and the end of the string, respectively.
- The
for loop continues as long as the left pointer is less than or equal to the right pointer.
- Inside the loop, we skip any non-alphanumeric characters using two
while loops.
- If the characters at the current
left and right positions are not equal (case-insensitively), we return false.
- After comparing the characters, we move both pointers inward (
left++ and right--) and continue checking.
- Edge Case:
- The function handles cases with non-alphanumeric characters, spaces, and empty strings correctly.
Time and Space Complexity
MetricComplexityTime ComplexityO(n)Space ComplexityO(1)
Time Complexity:
- The time complexity is O(n), where
n is the length of the string. We traverse the string once with two pointers, processing each character at most once.
Space Complexity:
- The space complexity is O(1). We use a constant amount of space, only storing a few pointers and variables.
Edge Cases
- Edge Case: Empty String
- Input:
""
- Output:
true
- Explanation: An empty string is trivially a palindrome since there’s nothing to compare.
- Edge Case: String with Spaces and Punctuation
- Input:
" , "
- Output:
true
- Explanation: The spaces and punctuation are ignored, and the string is considered a palindrome.
- Edge Case: Case-Insensitive Palindrome
- Input:
"Aa"
- Output:
true
- Explanation: The comparison is case-insensitive, so
"Aa" is considered a palindrome.
- Edge Case: Single Character String
- Input:
"a"
- Output:
true
- Explanation: A single character string is always a palindrome.
Conclusion
LeetCode 125: Valid Palindrome is a straightforward problem that involves checking whether a given string is a palindrome while ignoring spaces, punctuation, and case sensitivity. The solution, using the two-pointer technique, efficiently solves the problem in O(n) time, where n is the length of the string. The algorithm handles all edge cases, including empty strings, non-alphanumeric characters, and case differences, ensuring robustness.