Problem
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.
Given a string s
, return true
if it is a palindrome, or false
otherwise.
Example 1: Input: s = “A man, a plan, a canal: Panama” Output: true Explanation: “amanaplanacanalpanama” is a palindrome.
Example 2: Input: s = “race a car” Output: false Explanation: “raceacar” is not a palindrome.
Example 3: 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 * 105
s
consists only of printable ASCII characters.
Solution
Two Pointer - O(n) time - O(1) space
class Solution {
public:
bool isPalindrome(string s) {
for (int front = 0, back = s.length()-1; front <= back; front++, back--) {
while(front < s.length() -1 && !isalnum(s[front])) front++;
while(back > 0 && !isalnum(s[back])) back--;
if (front > back) return true;
if(tolower(s[front]) != tolower(s[back])) return false;
}
return true;
}
};
We can improve this significantly in terms of actual runtime and readability with a while loop
class Solution {
public:
bool isPalindrome(string s) {
int front = 0, back = s.length() - 1;
while(front <= back) {
if (!isalnum(s[front])) { front++; continue; }
if (!isalnum(s[back])) { back--; continue; }
if(tolower(s[front]) != tolower(s[back])) return false;
front++;
back--;
}
return true;
}
};
Even more improved is proper ordering of conditionals to avoid Branch Prediction misses
class Solution {
public:
bool isPalindrome(string s) {
int front = 0, back = s.length() - 1;
while(front <= back) {
if(isalnum(s[front]) && isalnum(s[back]) && tolower(s[front]) != tolower(s[back])) return false;
if (!isalnum(s[front])) { front++; continue; }
if (!isalnum(s[back])) { back--; continue; }
front++;
back--;
}
return true;
}
};