125. 验证回文串(C++)
题目
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: "A man, a plan, a canal: Panama"
输出: true
示例 2:
输入: "race a car"
输出: false
分析与题解
题目本身不难,笔者主要是为了落实自顶向下的思想:即着手一个问题时,首先思考大层次的逻辑结构,以高层次主干逻辑为主。
对于本体来说,主题思路为:
- 筛选出数字和字母,并对大小写进行转化(filter non number and char)
- 分别从头尾对是否为回文串进行比较(compare from both sides)
所以我们在主函数中可以写下如下框架:
class Solution {
public:
bool isPalindrome(string s) {
//自顶向下编程大框架
//1、filter out non number and char
//2、compare each pair of chars from both sides
string filteredS = _filterNonNumberAndChar(s);
return _compareFromBothSides(filteredS);
}
string _filterNonNumberAndChar(string s) {
}
bool _compareFromBothSides(string s) {
}
};
这种代码风格成为newspaper metaphor
,与报纸头版类似,将关键的函数写在前面,其他的私有函数和一些细节逻辑的函数使用子函数往文件或者类下放。接下来补充具体子函数的实现细节:
首先我们回忆下需要使用的C++内置函数:
- islower(char c):是否为小写字母
- isupper(char c):是否为大写字母
- isdigit(char c):是否为数字
关于大小写字母的转换,我们先查阅ASCⅡ表:
通过观察发现,对应大小写字母间的十进制ASCⅡ码相差32。因此函数具体实现如下:
string _filterNonNumberAndChar(string s) {
string tmp;
for (char c : s) {
if (islower(c) || isdigit(c)) tmp += c;
else if (isupper(c)) tmp += (c + 32);
}
return tmp;
}
在判断回文串时,我们设置两个flag分别从字符串末尾和首部进行比较,并且使用while循环作为终止条件。需要注意的是字符串下标从0进行计数,因此尾部起点为string.size()-1
,函数具体实现如下:
bool _compareFromBothSides(string s) {
int i = 0, j = s.size() - 1;
while (i < j) {
if (s[i] != s[j]) return false;
i++;
j--;
}
return true;
}
完整代码如下:
class Solution {
public:
bool isPalindrome(string s) {
//自顶向下编程大框架
//1、filter out non number and char
//2、compare each pair of chars from both sides
string filteredS = _filterNonNumberAndChar(s);
return _compareFromBothSides(filteredS);
}
string _filterNonNumberAndChar(string s) {
string tmp;
for (char c : s) {
if (islower(c) || isdigit(c)) tmp += c;
else if (isupper(c)) tmp += (c + 32);
}
return tmp;
}
bool _compareFromBothSides(string s) {
int i = 0, j = s.size() - 1;
while (i < j) {
if (s[i] != s[j]) return false;
i++;
j--;
}
return true;
}
};