最近由于感冒了,几天都没有刷题了,刚刚刷了一道不算很难的题,但是与之前的数值型问题相比明显有些生疏,所以后期仍需加强这方面的练习。
具体题目如下:
Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.
Note: For the purpose of this problem, we define empty string as valid palindrome.
Example 1:
Input: "A man, a plan, a canal: Panama"
Output: true
Example 2:
Input: "race a car"
Output: false
题意分析:
给定一个字符串,判断它是不是一个回文序列,仅考虑数字与字母,并忽略其他情况。注意:该题目中空字符串也算是回文序列。
解答如下:
方法一(对撞指针法)
先用两个指针r指向字符串的右端,l指向字符串的左端,让这两个指针齐头并进,跳过一切非数字与字母的情况,当两指针均指向数字或字母,然后通过转换大小写后判断两者是否相等,如果不相等则直接返回False,否则等到l=r时,返回True。
这里有几点需要注意:① 前面的 for (int l = 0; l < r; r--,l++) 中有 l < r,while(isalnum(s[r]) == false && l < r)依然需要 l < r,因为当while满足条件时r--,若不用l < r限制中,则有可能出现l > r的情况。②while(isalnum(s[l]) == false && l < r)中的isalnum(s[l])的返回值为非0或0,所以直接用while(!isalnum(s[l]))进行判断也是可以的,如while(!isalnum(s[l]) && l<r)完全等价于while(isalnum(s[l]) == false && l < r)。③toupper()函数将小写字母转化为大写字母,得到的其实是ASCII码,所以如果是数字就直接比较ASCII码,如果是小写字母先把它转为大写,然后在比较ASCII码。很显然toupper()函数可以用+32来替换,因为大写字母+32=小写字母。
class Solution {
public:
bool isPalindrome(string s) {
int r = s.size()-1;
int l = 0;
int n = s.size();
if (n == 1) //将字符串长度为1的直接判定为回文序列
return true;
for (int l = 0; l < r; r--,l++) {
while(isalnum(s[r]) == false && l < r)//判断当前元素是不是字母或数字,是的就结束循环,否则右端指针向左边移动 对于isalnum()函数,如果s[r]在0 ~ 9 a ~ z A ~ Z 中则返回值为非 0,否则返回 0
r--;
while(isalnum(s[l]) == false && l < r) //判断当前元素是不是字母或数字,是的就结束循环,否则左端指针向右边移动。
l++;
if(toupper(s[r]) != toupper(s[l])) //toupper()函数将小写字母转化为大写字母;tolower()函数是把字符串都转化为小写字母
return false;
}
return true;
}
};
提交后的结果如下:
方法二(子函数法)
分别建立两个子函数,next_zmorsz函数用于从字符串的左端开始找数字或字母,并返回下标;prev_zmorsz函数用于从字符串的右端开始找数字或字母,并返回下标。在主函数中依据返回来的下标找到数字或字母进行对比,若不相等则返回Fasle,否则继续调用两子函数继续查找,直到满足l=r时,则返回True。
这里有几点需要注意:① 当发现for(; l < r; )这种情况时,可以直接将其等价成while(l < r)。②这里的三句 int n = (int)s.size();
if (n == 1) return true; 其实可以等价于将for循环的判断条件改成 l <= r。③笔者发现,向子函数传递参数时,如果形参为int prev_zmorsz(const string& s, int id)比int prev_zmorsz(const string s, int id)要快很多倍,说明本题中参数传递更适合地址传递。
class Solution {
public:
bool isPalindrome(string s) {
int l = next_zmorsz(s, 0);
int r = prev_zmorsz(s, (int)s.size()-1);
int n = (int)s.size();
if (n == 1)
return true;
/* for(; l < r; ) {
if (toupper(s[r]) != toupper(s[l]))
return false;
l = next_zmorsz(s, l + 1);
r = prev_zmorsz(s, r - 1);
}
return true;*/
while(l < r) {
if (toupper(s[r]) != toupper(s[l]))
return false;
l = next_zmorsz(s, l + 1);
r = prev_zmorsz(s, r - 1);
}
return true;
}
private:
int next_zmorsz(const string& s, int id){
for (int i = id; i < s.size(); i++) {
if (isalnum(s[i]))
return i;}
return (int)s.size();
}
int prev_zmorsz(const string& s, int id){
for (int i = id; i >= 0; i--) {
if (isalnum(s[i]))
return i;}
return -1;
}
};
提交后的结果如下:
方法三(不用库函数法)
将方法一中用的库函数均改写掉,唯有toupper()函数改写行不通。即if (toupper(s[l]) != toupper(s[r])) return false;并不等价于 if ((s[l] != s[r]) && (s[l] != s[r] - 32) && (s[r] != s[l] - 32)) return false;
class Solution {
public:
bool isPalindrome(string s) {
int n = s.size();
if (n == 1) return true;
int l = 0, r = n - 1;
while (l < r) {
while ((l < r) && (!is_zmsz(s[l]))) l ++;
while ((l < r) && (!is_zmsz(s[r]))) r --;
if (toupper(s[l]) != toupper(s[r])) return false;
l ++;
r --;
}
return true;
}
inline bool is_zmsz(char a) {
return ((a >= 'a') && (a <= 'z')) ||
((a >= 'A') && (a <= 'Z')) ||
((a >= '0') && (a <= '9')) ;
}
};
提交后的结果如下:
日积月累,与君共进,增增小结,未完待续。