The Problem
Given a string s
, return true
if it is a palindrome, or false
otherwise.
A phrase is a palindrome if, after converting all uppercase letters into lowercase letters and removing all non-alphanumeric characters, it reads the same forward and backward. Alphanumeric characters include letters and numbers.
Examples
Input: s = "A man, a plan, a canal: Panama"
Output: true
Explanation: "amanaplanacanalpanama" is a palindrome.
Input: s = "race a car"
Output: false
Explanation: "raceacar" is not a palindrome.
Input: s = " "
Output: true
Explanation: s is an empty string "" after removing non-alphanumeric characters.
Since an empty string reads the same forward and backward, it is a palindrome.
Constraints
- 1 <= s.length <= 2 * 10^5
- s consists only of printable ASCII characters.
Brute Force Solution
func isPalindrome(_ s: String) -> Bool {
var newStr = ""
for c in s {
if c.isLetter || c.isNumber {
newStr += c.lowercased()
}
}
return newStr == String(newStr.reversed())
}
Explanation
Let’s start with the brute force solution. According to the description, we need to check if the string contains only lowercase, alphanumeric characters and reads the same forward and backward. In Swift, you can check this using the built-in isLetter
and isNumber
properties. Based on this information, we iterate through all characters in the s
string, verify that each character is a letter or number, update newStr
with the current lowercased
character, and compare the result with its reversed
version.
Time/Space Complexity
- Time complexity: O(n)
- Space complexity: O(n)
Solution - 2 - Optimal
func isPalindrome(_ s: String) -> Bool {
let s = Array(s)
var l = 0
var r = s.count - 1
while l < r {
if !isAlnum(s[l]) {
l += 1
continue
}
if !isAlnum(s[r]) {
r -= 1
continue
}
if s[l].lowercased() != s[r].lowercased() {
return false
}
l += 1
r -= 1
}
return true
}
func isAlnum(_ c: Character) -> Bool {
let cAscii = c.asciiValue!
return (
cAscii >= Character("A").asciiValue! && cAscii <= Character("Z").asciiValue!
||
cAscii >= Character("a").asciiValue! && cAscii <= Character("z").asciiValue!
||
cAscii >= Character("0").asciiValue! && cAscii <= Character("9").asciiValue!
)
}
Explanation
To solve the problem optimally, based on the description, we need to determine if each character is alphanumeric and lowercase. We can accomplish this by introducing an isAlnum
helper function that checks if a character is alphanumeric within the loop, using the two-pointer technique. For example, in the array "car rac"
, the first left and right characters are both "c"
, the second are both "a"
, and the third are both "r"
. Following this logic, we can confirm that the input string s
is a palindrome.
Time/Space Complexity
- Time complexity: O(n)
- Space complexity: O(1)