最短回文串
难度:
标签:
题目描述
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
示例 1:
输入:s = "aacecaaa" 输出:"aaacecaaa"
示例 2:
输入:s = "abcd" 输出:"dcbabcd"
提示:
0 <= s.length <= 5 * 104
s
仅由小写英文字母组成
代码结果
运行时间: 41 ms, 内存: 16.2 MB
// 思路:
// 1. 使用相同的思路,将s反转并构建最长回文前缀,
// 但使用Java Stream处理字符串操作
import java.util.stream.IntStream;
import java.util.stream.Collectors;
public class SolutionStream {
public String shortestPalindrome(String s) {
int n = s.length();
String reverse_s = new StringBuilder(s).reverse().toString();
String combined = s + "#" + reverse_s;
int[] prefix = new int[combined.length()];
IntStream.range(1, combined.length()).forEach(i -> {
int j = prefix[i - 1];
while (j > 0 && combined.charAt(i) != combined.charAt(j)) {
j = prefix[j - 1];
}
if (combined.charAt(i) == combined.charAt(j)) {
j++;
}
prefix[i] = j;
});
return IntStream.range(0, n - prefix[combined.length() - 1])
.mapToObj(reverse_s::charAt)
.map(String::valueOf)
.collect(Collectors.joining()) + s;
}
}
解释
方法:
这个题解采用了二分查找的思路。首先将原字符串 s 翻转得到 s1。如果 s 本身就是回文串,直接返回 s。否则,通过二分查找的方式,在 s1 中查找 s 的前缀,找到最长的能够形成回文串的前缀。查找过程中,使用双指针 a 和 b 分别指向查找范围的起始和结束位置,每次取中点 c,判断 s1 中是否存在 s[:c] 子串。如果存在,则判断 s1[j+c:j+m] 与 s[c:m] 是否相等(其中 j 为 s[:c] 在 s1 中的起始位置,m 为 s[:c] 的中点),如果相等则找到了最长的回文前缀,返回 s1[:j] + s。如果不相等,则将查找范围缩小到 [c, b]。如果 s[:c] 在 s1 中不存在,则将查找范围缩小到 [a, c-1]。最后,如果没有找到任何回文前缀,则返回 s1[:-1] + s。
时间复杂度:
O(n log n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么要将原字符串翻转得到 s1 来进行处理?这样做的目的是什么?
▷🦆
在二分查找中,你是如何确定查找区间 [a, b] 的初始值及其调整逻辑的?
▷🦆
当 s1.find(s[:c]) 返回 -1 时,为什么选择将查找范围调整到 [a, c-1] 而不是其他区间?
▷🦆
算法中提到,如果 s1[j+c:j+m] 与 s[c:m] 相等,则找到了最长的回文前缀。这里的判断逻辑是怎样的?能否详细解释一下这部分的比较机制?
▷相关问题
最长回文子串
给你一个字符串 s
,找到 s
中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串。
示例 1:
输入:s = "babad" 输出:"bab" 解释:"aba" 同样是符合题意的答案。
示例 2:
输入:s = "cbbd" 输出:"bb"
提示:
1 <= s.length <= 1000
s
仅由数字和英文字母组成
找出字符串中第一个匹配项的下标
给你两个字符串 haystack
和 needle
,请你在 haystack
字符串中找出 needle
字符串的第一个匹配项的下标(下标从 0 开始)。如果 needle
不是 haystack
的一部分,则返回 -1
。
示例 1:
输入:haystack = "sadbutsad", needle = "sad" 输出:0 解释:"sad" 在下标 0 和 6 处匹配。 第一个匹配项的下标是 0 ,所以返回 0 。
示例 2:
输入:haystack = "leetcode", needle = "leeto" 输出:-1 解释:"leeto" 没有在 "leetcode" 中出现,所以返回 -1 。
提示:
1 <= haystack.length, needle.length <= 104
haystack
和needle
仅由小写英文字符组成
回文对
给定一个由唯一字符串构成的 0 索引 数组 words
。
回文对 是一对整数 (i, j)
,满足以下条件:
0 <= i, j < words.length
,i != j
,并且words[i] + words[j]
(两个字符串的连接)是一个回文串。
返回一个数组,它包含 words
中所有满足 回文对 条件的字符串。
你必须设计一个时间复杂度为 O(sum of words[i].length)
的算法。
示例 1:
输入:words = ["abcd","dcba","lls","s","sssll"]
输出:[[0,1],[1,0],[3,2],[2,4]]
解释:可拼接成的回文串为 ["dcbaabcd","abcddcba","slls","llssssll"]
示例 2:
输入:words = ["bat","tab","cat"]
输出:[[0,1],[1,0]]
解释:可拼接成的回文串为 ["battab","tabbat"]
示例 3:
输入:words = ["a",""] 输出:[[0,1],[1,0]]
提示:
1 <= words.length <= 5000
0 <= words[i].length <= 300
words[i]
由小写英文字母组成