题目链接:https://leetcode.com/problems/shortest-palindrome/
Given a string S, you are allowed to convert it to a palindrome by adding characters in front of it. Find and return the shortest palindrome you can find by performing this transformation.
For example:
Given "aacecaaa"
, return "aaacecaaa"
.
Given "abcd"
, return "dcbabcd"
.
思路:也是蛋疼的一题啊,刚开始用中心法求回文数的方法求前缀最大的回文数是多少,一直超时,时间复杂度为O(n*n),代码如下:
class Solution { public: string shortestPalindrome(string s) { int len = s.size(); if(len == 0) return ""; int left, right, i = (len*2 -1)/2 ; string result; int sum = 0; while(i >= 0) { sum++; left = i/2; right = i%2==1?(i/2+1):i/2;//奇偶数right指针位置不一样 while(left >= 0) { if(s[left] == s[right]) { left--; right++; } else break; } if(left < 0) break; i--; } for(int i = len-1; i >= right; i--) result += s[i]; result += s; return result; } };
本题其实是求最大的前缀和后缀的匹配数,例如字符串为abbad,可以看到我们只要在前面加一个d就能构成一个最短的回文数,因为其前缀abba是回文。现在我们的任务就是寻找最大回文前缀。
接下来我们将其逆转之后为dabba,再将其合并成一个字符串abbad$dabba,可以看出要求最大的回文前缀,只需要求出最大的前缀和后缀相等的长度。
这种时间复杂度为O(n),真是神奇的一个算法。
代码如下:
class Solution { public: string shortestPalindrome(string s) { int len = s.size(); if(len == 0) return ""; string revStr = s; reverse(revStr.begin(), revStr.end()); string str = s + "$" + revStr; vector<int> table(str.size(), 0); int index = 0; for(int i = 1; i< str.size(); i++) { if(str[index] == str[i])//如果当前匹配 { table[i] = table[i-1]+1; index++; } else//如果当前不匹配 { index = table[i-1]; while(index > 0 && str[index] != str[i])//如果当前长度的不匹配,就缩短一位看是否匹配 index = table[index-1]; if(str[i]==str[index]) index++; table[i] = index; } } int maxMatch = table[str.size()-1]; string result = revStr.substr(0, len-maxMatch) + s; return result; } };
https://leetcode.com/discuss/64309/clean-kmp-solution-with-super-detailed-explanation