题目链接:https://leetcode.com/problems/shortest-palindrome/
题意:已知一个字符串s,在其前面添加最少的字符数使其成为一个回文串。
思路:设字符串s的长度为len,则最多肯定是添加len长度的字符,即将s倒置。什么情况可以少添加字符呢?当s的前缀是一个回文串时,则由于该部分已经是回文串,不需要再为其匹配,添加该段后面的回文部分即可,因此只需要求字符串s的最大前缀回文串。剩下的部分按照对应位置添加即可。
求字符串的最大前缀回文子串,KMP算法和manacher算法都可以,KMP算法即为$next[i]==i$的最大$i$,manacher算法可以求出以第$i$个字符结尾的回文子串长度,因此查找出$len[i]==i$的最大值即可。
只给出manacher算法的代码
class Solution { public: //manacher算法初始化数组 string init(const string &s) { string s1; s1 += '$'; for (int i = 0;i < s.size();i++) { s1 += '#'; s1 += s[i]; } s1 += '#'; s1 += ')'; return s1; } //manacher算法 int manachar(string s, int *Len, int len) { int ans = 1; int mx = 0, pos = 0; for (int i = 1;i <= len;i++) { //mx为回文串最右端位置,pos为回文串中间位置 if (mx > i) Len[i] = min(mx - i, Len[2 * pos - i]); else Len[i] = 1; while (s[i - Len[i]] == s[i + Len[i]]) Len[i]++; if (Len[i] + i > mx) { pos = i; mx = Len[i] + i; } if (Len[i] == i) ans = max(Len[i] - 1, ans); } return ans; } string shortestPalindrome(string s) { if (s.empty()) return ""; int *Len = new int[s.size() * 2 + 2]; //此时z为最长前缀回文串 int z = manachar(init(s), Len, s.size() * 2 + 1) ; //此时z为s匹配后的总长度 z = (s.size() - z) * 2+z; string ans; for (int i = s.size()-1;i >= 0;i--) { ans += s[i]; } int cnt = ans.size(); while (ans.size() < z) { ans += ans[z -1 - cnt]; cnt++; } reverse( ans.begin(), ans.end()); return ans; } };