给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入: "aacecaaa"
输出: "aaacecaaa"
示例 2:
输入: "abcd"
输出: "dcbabcd"
思路分析:首先我们需要确定最短的回文中心在哪里。
回文中心分两种情况:(我们从正中间向右扫描,穷举回文中心)
1、形如 "abbacd" 这种,中心为两个字符,中心下标为1、2两个(特殊情况为“aabcd”中心下标为0,1)
2、形如 "aacecaaa" ,中心为一个字符串,中心下标为3(特殊情况为“abced”中心为下标0)
找到中心后,我们将对称部分后面的字符串截出,然后反转,最后加上原字符串就是最短的回文字符串。
class Solution {
public:
string shortestPalindrome(string s) {
int sSize = s.size();
if (sSize < 2){
return s;
}
int beginIndex, endIndex;
string result;
int midIndex = sSize / 2 - 1 + sSize % 2;//计算这个字符串的中心
//对中心进行穷举
while (midIndex >= 0){
//对于两个中心的情况
if (s[midIndex] == s[midIndex + 1] && isTrueMid(s, midIndex - 1, midIndex + 2)){
result = s.substr(midIndex * 2 + 2, sSize);//截出后面剩余的部分
break;
}
//对于一个中心的特殊情况
if (midIndex == 0){
result = s.substr(midIndex + 1, sSize);
break;
}
//对于一个中心的一般情况
if (isTrueMid(s, midIndex - 1, midIndex + 1)){
result = s.substr(midIndex * 2 + 1, sSize);
break;
}
midIndex -= 1;
}
reverse(result.begin(), result.end());//反转
result += s;//加上原字符串就是最短的回文字符串
return result;
}
//判断beginIndex和endIndex两个是否相等,即中心是否有效
bool isTrueMid(string &s, int beginIndex, int endIndex){
while (beginIndex >= 0 && s[beginIndex] == s[endIndex]){
beginIndex -= 1;
endIndex += 1;
}
return beginIndex == -1;
}
};
方法二:首先将s的反转与s拼接,然后去掉中间对称的部分即可。
class Solution {
public:
string shortestPalindrome(string s) {
string rs = s;
reverse(rs.begin(), rs.end());//反转
string m = s + "#" + rs;//反转与原字符串拼接
vector<int> next(m.size(), 0);
for(int j = 1, k = 0; j < m.size(); j++)
{
while(k > 0 && m[j] != m[k])
k = next[k - 1];
if(m[j] == m[k])
k++;
next[j] = k;
}
int pos = next[m.size() - 1];
int len = rs.size() - pos;
return rs.substr(0, len) + s;
}
};