一、题目描述与要求
125. 验证回文串 - 力扣(LeetCode)
题目描述
如果在将所有大写字符转换为小写字符、并移除所有非字母数字字符之后,短语正着读和反着读都一样。则可以认为该短语是一个 回文串 。
字母和数字都属于字母数字字符。
给你一个字符串 s,如果它是 回文串 ,返回 true ;否则,返回 false 。
示例
示例1:
输入: s = "A man, a plan, a canal: Panama"
输出:true
解释:"amanaplanacanalpanama" 是回文串。
示例2:
输入:s = "race a car"
输出:false
解释:"raceacar" 不是回文串。
示例3:
输入:s = " "
输出:true
解释:在移除非字母数字字符之后,s 是一个空字符串 "" 。
由于空字符串正着反着读都一样,所以是回文串。
提示
1 <= s.length <= 2 * 105
s
仅由可打印的 ASCII 字符组成
二、解题思路
总的思路:
首先根据题目要求可以有两种大的解题方法:一是对数组本身进行修改,将其改成要进行判断的形式然后判断其是否为回文串;二是利用双指针的方式,对于要排除的字符选择跳过,以此来判断整个字符串是否为回文串。【下面提到的下标变量指的是用来指示下标的整型变量】
对于第一种方法,则需要我们首先将数组中的所有大写字符都转成小写字符,其实也就是26个字母的大写转成小写,利用“ch=ch+32”即可实现。然后就是将数组中所有非字母数字字符进行移除,也就是删去除字母和数字以外的其他字符,可以利用覆盖的思想,在每次找到非字母数字字符时将后面所有字符往前覆盖,覆盖只需要利用到一个下标变量(时间较长)。也可以使用两个下标变量,一个用来遍历整个数组,另一个用来记录修改后的数组。然后就是直接对修改后的数组首尾字符进行比较来判断其是否为回文串。
对于第二种方法,则需要我们设置一个判定条件,即只有当两个字符都是字母或者数字才对其进行比较,一旦有一方不是,则需要寻找下一个字符用来比较,也就是所谓的“跳过”。这一方法需要利用到“双指针”,也就是两个下标变量。两方都是的情况下则只需要修改大写字母为小写,然后进行判断是否相同,相同则移动指针继续比较直至遍历结束/发现不是回文串则结束。【在实现这一方法的过程中,就是判断字符是否是字母/数字字符的代码比较长,看起来很乱,因而可以选择将其单独写成一个函数】【修改大写字母为小写可以在判断字符前把整个数组都进行修改,也可以在判断后在对其进行修改】
具体步骤:
方法一:
①遍历数组,将大写字符全部转换成小写字符
②将数组中所有非字母数字字符进行移除【可以分为利用几个下标变量】
③获取数组长度
④判断修改后的字符串是否为回文串
方法二:
①获取数组长度
②将数组中的所有大写字符转成小写字符
③判断首尾字符是否为字母数字字符,并判断是否相等,然后移动指针,直至获得结果
三、具体代码【C语言】
①只采用一个下标变量来对数组进行修改(覆盖)【超时,但步骤清晰,可用于理解】
bool isPalindrome(char* s) {
int i = 0, j = 0;
for (int i = 0; s[i] != '\0'; i++) { //遍历数组,将大写字符全部转换成小写字符
if (s[i] >= 'A' && s[i] <= 'Z') {
s[i] += 32;
}
}
while (s[i] != '\0') {
if ((s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z')) //是数字或者字母字符 访问下一个
{
i++;
}
else { //不是数字或者字符 覆盖并继续检查
for (j = i; s[j] != '\0'; j++) {
s[j] = s[j + 1];
}
s[j - 1] = '\0';//此时j-1指向最后一个字符的后面第一位
}
}
int len = strlen(s);
//k=j-2是因为,数组下标从0开始,j-1是结束符的下标,j-2就是最后一个字符的下标
for (int i = 0, k = len - 1; i < k; i++) {
if (s[i] != s[k])
return false;
else k--;
}
return true;
}
②对①进行修改,即利用两个下标变量来实现数组的修改【大写改小写与覆盖同时进行】【最快】
bool isPalindrome(char* s) {
int i = 0, j = 0;
for (int i = 0; s[i] != '\0'; i++) { //遍历数组,将大写字符全部转换成小写字符
if (s[i] >= 'A' && s[i] <= 'Z') {
s[j++] = s[i] + 32;
}
else if ((s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z')) {
s[j++] = s[i];
}
}
//此时j指向调整后的数组的结束符
for (int i = 0, k = j - 1; i < k; i++) {
if (s[i] != s[k])
return false;
else k--;
}
return true;
}
③不对数组进行修改,直接进行比较
bool Judge(char ch) {
if ( (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) {
return true;
}
else {
return false;
}
}
bool isPalindrome(char * s){
int j=strlen(s)-1;
for(int i=0;s[i]!='\0';i++){ //遍历数组,将大写字符全部转换成小写字符
if (s[i] >= 'A' && s[i] <= 'Z') s[i]+=32;
}
for (int i = 0; s[i]!='\0'; i++) {
while(i<j){
if(Judge(s[i])&&Judge(s[j])){
if(s[i]!=s[j]) return false;
i++; j--;
}
else if(!Judge(s[i])){
i++;
}
else{
j--;
}
}
}
return true;
}