题目链接:https://leetcode.com/problems/shortest-palindrome/submissions/
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入: "aacecaaa"
输出: "aaacecaaa"
示例 2:
输入: "abcd"
输出: "dcbabcd"
思路:
暴力肯定超时,所以用kmp来解决。
让在前面补一些字符使得给定的字符串变成回文,观察可以发现我们需要添加多少个字符与给定字符串的前缀子串回文的长度有关.也就是说去掉其前缀的回文子串,我们只需要补充剩下的子串的逆序就行了,举个栗子:aacecaaa,其前缀的最大回文子串是aacecaa,剩下了一个a,因此我们只需要在前面加上一个a的逆序a就行了.再例如abcd,其前缀的最大回文是a,因此剩下的子串就为bcd,所以需要在前面加上bcd的逆序,就变成了dcbabcd.所以这样问题就转化为求字符串的前缀最大回文长度.
然后就转化成了求取字符串s中的最长相同前后缀(不能是其本身)
状态定义:
prefix(x) -------- 字符串s中[0, x]范围内的最长相同前后缀(不能是其本身)的长度
状态转移:
首先是初始化,prefix(0)显然是0,因为[0, 0]范围内的字符串长度为1,其最长相同前后缀根本不存在。
对于i在[1, n - 1](其中n为字符串s的长度)范围内的值:
(1)令 t 记录prefix(x - 1)的值,如果 t 大于0且s中 t 位置的字符和第i个字符不相同,那么我们就需要重设 t 的值为prefix(t - 1)。
(2)如果s中第i个字符与第t个字符相同,prefix[i]=t+1;
(3)prefix(i) = 0;
上述状态转移过程可能很难理解,以一个例子——“ABABCABAA”来说明,其子串如下:
A -------------------------------------------------- 0
AB ------------------------------------------------ 0
ABA ---------------------------------------------- 1
ABAB -------------------------------------------- 2
ABABC ------------------------------------------ 0
ABABCA ---------------------------------------- 1
ABABCAB -------------------------------------- 2
ABABCABA ------------------------------------ 3
ABABCABAA ---------------------------------- 1
对由ABAB求得ABABC这个过程进行分析:
C和A不相等,因此结果不可能是3,如果是ABABA,则结果是3。ABAB的结果是2,因此我们知道AB和AB相同,但是第一个AB之后跟着的是A,依然和C不相同。我们继续看AB,AB的结果是0,因此我们知道AB中A和B不相同,而C和A不相同,因此结果是0。
对由ABABCABA求得ABABCABAA这个过程进行分析:
A和B不相等,因此结果不可能是4,如果是ABABCABAB,则结果是4。ABABCABA的结果是3,因此我们知道ABA和ABA相同,但是第一个ABA之后跟着的是B,依然和A不相同。我们继续看ABA,ABA的结果是1,但是第一个A之后跟着的是B,依然和A不相同。我们继续看A,结果是0,结束while循环。这个A和A相同,因此其值加1变成1。
时间复杂度和空间复杂度均是O(n),其中n为字符串s的长度。
AC 3ms:
class Solution {
public String shortestPalindrome(String s) {
int n=s.length();
String str=s+"#"+new StringBuilder(s).reverse().toString();
int[] prefix=new int[str.length()];
getTable(str,prefix);
return new StringBuilder(
s.substring(prefix[prefix.length-1])).reverse().toString()+s;
}
public void getTable(String s,int[] prefix){
prefix[0]=0;
for(int i=1;i0&&s.charAt(i)!=s.charAt(t))
t=prefix[t-1];
if(s.charAt(i)==s.charAt(t))
prefix[i]=t+1;
else
prefix[i]=0;
}
}
}
reference:
https://blog.csdn.net/qq508618087/article/details/51641392
https://blog.csdn.net/qq_41231926/article/details/86747126