携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第13天,点击查看活动详情
题目(Shortest Palindrome)
链接:https://leetcode-cn.com/problems/shortest-palindrome
解决数:398
通过率:38.6%
标签:字符串 字符串匹配 哈希函数 滚动哈希
相关公司:microsoft netease bloomberg
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入: s = "aacecaaa"
输出: "aaacecaaa"
示例 2:
输入: s = "abcd"
输出: "dcbabcd"
提示:
0 <= s.length <= 5 * 104s仅由小写英文字母组成
思路
从暴力法可以看出,其实就是求 s 的「最长回文前缀」,然后在 rev_s 的后缀中砍掉这个回文,再加到 s 前面。
这个最长前缀是回文的,它翻转之后等于它自己,出现在 rev_s 的后缀,这不就是公共前后缀吗?KMP 的 next 数组记录的就是一个字符串的每个位置上,最长公共前后缀的长度。公共前后缀指的是前后缀相同。
因此,我们 “制造” 出公共前后缀,去套 KMP。
s:abab,则 s + '#' + rev_s,得到 str :abab#baba。
求出 next 数组,最后一项就是 str 的最长公共前后缀的长度,即 s 的最长回文前缀的长度。
如果不加 #,'aaa'+'aaa'得到'aaaaaa',求出的最长公共前后缀是 6,但其实想要的是 3。
代码
const shortestPalindrome = (s) => {
const rev_s = s.split('').reverse().join('');
const str = s + "#" + rev_s;
const next = new Array(str.length).fill(0);
// 抽出来,方便学习记忆,这是我写的模板
const kmp = (next, str) => {
next[0] = 0;
let len = 0;
let i = 1;
while (i < str.length) {
if (str[i] == str[len]) {
len++;
next[i] = len;
i++;
} else {
if (len == 0) {
next[i] = 0;
i++;
} else {
len = next[len - 1];
}
}
}
};
kmp(next, str);
const maxLen = next[str.length - 1]; // 最长回文前缀的长度
const add = s.substring(maxLen).split('').reverse().join('');
return add + s;
};
const shortestPalindrome = (s) => { // s:ananab
const len = s.length;
const rev_s = s.split('').reverse().join(''); // rev_s:banana
for (let i = len; i >= 0; i--) { // ananab==banana?、anana==anana?、……
if (s.substring(0, i) == rev_s.substring(len - i)) {
return rev_s.substring(0, len - i) + s; // 返回 b + ananab
}
}
}
也可以判断 s 的前缀部分是否回文(前缀部分尽量长),但循环套循环的,代码超时了:
120 / 120 test cases passed, but took too long.
const isPalindrome = (s) => {
let i = 0, j = s.length - 1;
while (i < j) {
if (s[i] !== s[j]) return false;
i++;
j--;
}
return true;
};
const shortestPalindrome = (s) => {
const len = s.length;
for (let i = len; i >= 0; i--) {
const prefix = s.substring(0, i); // 前缀部分,从大的开始考察
if (isPalindrome(prefix)) { // 一旦是回文就准备return结果
const add = s.substring(i).split('').reverse().join('');
return add + s;
}
}
};