给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入: “aacecaaa”
输出: “aaacecaaa”
示例 2:
输入: “abcd”
输出: “dcbabcd”
力扣214-最短回文串【kmp】
代码实现:
class Solution {
public static String shortestPalindrome(String s) {
StringBuilder r = new StringBuilder(s).reverse();
String str = s + "#" + r;
int[] next = next(str);
String prefix = r.substring(0, r.length() - next[str.length()]);
return prefix + s;
}
private static int[] next(String P) {
int[] next = new int[P.length() + 1];
next[0] = -1;
int k = -1;
int i = 1;
while (i < next.length) {
if (k == -1 || P.charAt(k) == P.charAt(i - 1)) {
next[i++] = ++k;
} else {
k = next[k];
}
}
return next;
}
}
结合官方解释更香 |
如果是回文串 aacecaaa
debug:
主流程:
next数组 KMP的next[0] = -1;
next[j]=x就是指[ 1 , x ]与 [ j-x+1 , j ] 的元素是相同的
//next[ ]=
//01000122012234567
//aacecaaa#aaacecaa
8-7=1
r.substring[0,1)
prefix=a
prefix + s = aaacecaaa;
kmp算法
首先我们需要理解kmp算法。
具体的kmp算法实现原理以及next数组如何计算请看这个视频,https://www.bilibili.com/video/BV1jb411V78H 单凭理解来说,个人觉得全网讲解最详细易懂的。
利用kmp解题的完整思路
看原题:
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
- 解题思路:
在字符串前面添加字符,意味我们得在前缀开始找以前缀为首的最大回文子串。然后在把后面的部分取反添加到原字符串前,就成功得到原题方式转换的最短字符串。
为什么需要取反?
- 使用取反的心路历程:
当你理解kmp算法的时候,你知道了next是储存匹配失败和成功的跳转,== 的目的是找出模式字串前缀为首的子串和后缀为尾的字串相同的,属于成功匹配。!= 就是匹配失败的情况。kmp的核心是模式字符串与目标字符串的匹配。
想利用kmp找题意的转换最短字符串,需要改进字符串本身。直接使用kmp找原字符串的以前缀为首的最大回文串,你会发现存在bug,aacecaaa只剩aa。前缀为首的子串是满足的,但我们还需要确定是回文的,所以我们需要在原字符串后面加它取反的字符串。