原题地址:https://leetcode-cn.com/problems/shortest-palindrome/
题目描述:
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入: "aacecaaa"
输出: "aaacecaaa"
示例 2:
输入: "abcd"
输出: "dcbabcd"
解题方案:
本题核心思想是采用KMP算法,参考地址:https://segmentfault.com/a/1190000003797346
大学本科就学过KMP算法,算法比较知名,一直还没怎么弄懂。。。。
字符串的处理方式也是很巧妙的,首先得到最长的回文串,然后再采用KMP算法进行删减。
代码:
class Solution {
public:
string shortestPalindrome(string s) {
// 将字符串反转后拼接到后面
string rev(s);
reverse(rev.begin(), rev.end());;
string combine = s + "#" + rev;
// 计算LPS表值
vector<int> lps(combine.length(), 0);
int remove = getLPS(combine, lps);
// 去掉后缀后,将反转字符串拼回前面
string prepend = rev.substr(0, rev.length() - remove);
return prepend + s;
}
int getLPS(string s, vector<int>& lps){
// i是后缀末尾的指针,j是前缀末尾的指针
int j = 0, i = 1;
// 从j=0,i=1开始找,错开了一位
while(i < s.length()){
// 如果字母相等,则继续匹配,最长相同前后缀的长度也加1
if(s[i] == s[j]){
lps[i] = j + 1;
i ++;
j ++;
// 如果不同
} else {
// 如果前缀末尾指针还没退回0点,则找上一个子前缀的末尾位置
if(j != 0){
j = lps[j - 1];
// 如果退回0点,则最长相同前后缀的长度就是0了
} else {
lps[i] = 0;
i ++;
}
}
}
return lps[lps.size() - 1];
}
};