Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
For example,
"A man, a plan, a canal: Panama"
is a palindrome.
"race a car"
is not a palindrome.
2. 解析
(1)题目的意思是,给你一个字符串,判断这个字符串是不是回文串,只考虑字母数字的字符,忽略大小写。这里字母数字的字符包括:0~9,A~Z,a~z。
这道题本来是很简单的,但无奈第2次刷的时候,却碰到了“0P”这个测试用例,不知是哪位心思缜密的道友提供的,这里为你点赞。如果不考虑“0P”这种跨越字母和数字的测试用例,我们在比较两个合法的字符时,只需要判断该字符是否相等,或者绝对值之差为32(‘a’-'A' = 32)即可,如果满足就继续往下比较,否则直接返回false,遍历结束true。
bool isPalindrome(string s) {
if(s.empty())return true;
for(int i = 0, j = s.size() - 1; i < j; ++i,--j)
{
while(i < j && !isAlphanumeric(s[i]))++i;
while(i < j && !isAlphanumeric(s[j]))--j;
if(!(s[i] == s[j] || s[i] + 32 == s[j] && s[i] - 32 == s[j]))
return false;
}
return true;
}
(2)接下来着重讨论“0P”这种跨越数字和字符的测试用例的情况,首先字符0~9的ASCII码范围是48~57, 字符A~Z的ASCII范围是65~90, a~z的ASCII码范围是97~122。然后,我们将0~9的ASCII码加上32,范围变成了80~89,发现恰好落在字符P(80)~Y(89)的范围内,这是s[i] + 32 == s[j]条件为true, 于是出现bug,反过来,“P0”这种情况也是true。要解决这个问题其实很简单,由于0~9的ASCII码向后平移32个长度是不在a~z的范围之内,那么a~z的ASCII码向前平移32个长度也不会和0~9码重合,因此,我们只需要将字符串中的大写字符全部转换成对应的小写字母即可,转换之后,合法字符只剩0~9和a~z,我们只需要比较两个字符是否相等即可。最终代码如下:
class Solution {
public:
bool isPalindrome(string s) {
if(s.empty())return true;
for(int i = 0, j = s.size() - 1; i < j; ++i,--j)
{
while(i < j && !isAlphanumeric(s[i]))++i;
while(i < j && !isAlphanumeric(s[j]))--j;
if(toLowercase(s[i]) != toLowercase(s[j]))
return false;
}
return true;
}
bool isAlphanumeric(char ch)
{
return ch >= '0' && ch <= '9' || ch >= 'a' && ch <= 'z' || ch >= 'A' && ch <= 'Z';
}
char toLowercase(char ch)
{//notice the case "0P"
if(ch >= 'A' && ch <= 'Z')
ch += 32;
return ch;
}
};
写这篇博文,只是想把自己觉得题目中涉及到的比较好的知识提炼出来和大家一起分享,code大神可以直接略过。
水平有限,不合理或不完善地方敬请指正,谢谢!