题目链接:
题目描述:
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。
示例 1:
输入: "aba"
输出: True
示例 2:
输入: "abca"
输出: True
解释: 你可以删除c字符。
注意:
- 字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。
算法:
此题应该是125. 验证回文串的升级版。第125题只需要先去掉空格,然后字母统一转化成大写或者小写,判断一下即可。
对于判断回文串,有两种方法:
- 运用string类型的reverse方法,创建一个新的字符串,然后与原来的字符串进行逐个比较,如果比较到最后一位,则返回true,否则如果有不对,则返回false。
- 直接对字符串的头尾进行比较,一直比较到中间一个,如果全部相同,则返回true,否则返回false。
显然第一种方法编码效率比较高,而且逻辑更加清楚,但是需要的代价比较大。显然,两种算法的时间复杂度都是O(n),而空间复杂度则一个是O(n),一个是O(1),第二种方法更优。但是效率和空间只要差距不太大都是可以接受的。对于现在的计算机的效率,对于程序员来说,如果写出逻辑清楚的代码更加重要。所以一般推荐使用第一种方法,只有在有些对于效率比较苛刻的情况下才考虑第二种方法。
就这题来说,如果使用第一种方法,逐个比较的时候发现有一位不一样,则不知道这一位是字符串s1上面多出来的,还是字符串s2上面多出来的。因此可靠的办法是把两者对应的字母分别删去(当然要同时删掉后面的),再比较是否相同。
而如果使用第二种方法,则问题同样在于不知道多出来的字母是在字符串的前半部分还是后半部分,这个时候就不需要进行删除操作了,只需要往前进一位或者往后退一位,再进行比较即可。
该题思路比较简单,主要是使用第二种方法去做,对编码能力有些要去。这是一种锻炼。
代码:
第一种方法:
class Solution {
public:
bool validPalindrome(string s) {
string n = s;
reverse(s.begin(),s.end());
if (n.compare(s) == 0)
return true;
for (int i = 0; i < s.length(); i++) {
if (n[i] != s[i]) {
string t1 = n;
string t2 = s;
t1.erase(t1.begin() + i);
t2.erase(t2.begin() + s.length() - i - 1);
if (t1.compare(t2) == 0)
return true;
t1 = n;
t2 = s;
t1.erase(t1.begin() + s.length() - i - 1);
t2.erase(t2.begin() + i);
if (t1.compare(t2) == 0)
return true;
return false;
}
}
return true;
}
};
第二种方法:
class Solution {
public:
bool validPalindrome(string s) {
int i = 0, j = s.length() - 1;
while (i < s.length() / 2) {
if (s[i] != s[j])
break;
i++;
j--;
}
if (i == s.length() / 2)
return true;
if (s[i + 1] != s[j] && s[i] != s[j - 1])
return false;
int posI = i + 1, posJ = j;
while (posI < (s.length() + 1) / 2) {
if (s[posI] != s[posJ])
break;
posI++;
posJ--;
}
if (posI >= (s.length() + 1) / 2)
return true;
posI = i, posJ = j - 1;
while (posI < (s.length() - 1) / 2) {
if (s[posI] != s[posJ])
break;
posI++;
posJ--;
}
if (posI >= (s.length() - 1) / 2)
return true;
return false;
}
};
网友评论