给定一组 互不相同 的单词, 找出所有 不同 的索引对 (i, j)
,使得列表中的两个单词, words[i] + words[j]
,可拼接成回文串。
示例 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]
由小写英文字母组成
方法一:字符串哈希
字符串哈希是把一个任意长度的字符串映射成一个非负整数,并且其冲突的概率几乎为
取一固定值
一般来说,取 unsigned long long
类型存储这个
除了在极特殊构造的数据上,上述
方法二:前缀树
class Solution:
def palindromePairs(self, words: List[str]) -> List[List[int]]:
d = {w: i for i, w in enumerate(words)}
ans = []
for i, w in enumerate(words):
for j in range(len(w) + 1):
a, b = w[:j], w[j:]
ra, rb = a[::-1], b[::-1]
if ra in d and d[ra] != i and b == rb:
ans.append([i, d[ra]])
if j and rb in d and d[rb] != i and a == ra:
ans.append([d[rb], i])
return ans
class Solution {
private static final int BASE = 131;
private static final long[] MUL = new long[310];
private static final int MOD = (int) 1e9 + 7;
static {
MUL[0] = 1;
for (int i = 1; i < MUL.length; ++i) {
MUL[i] = (MUL[i - 1] * BASE) % MOD;
}
}
public List<List<Integer>> palindromePairs(String[] words) {
int n = words.length;
long[] prefix = new long[n];
long[] suffix = new long[n];
for (int i = 0; i < n; ++i) {
String word = words[i];
int m = word.length();
for (int j = 0; j < m; ++j) {
int t = word.charAt(j) - 'a' + 1;
int s = word.charAt(m - j - 1) - 'a' + 1;
prefix[i] = (prefix[i] * BASE) % MOD + t;
suffix[i] = (suffix[i] * BASE) % MOD + s;
}
}
List<List<Integer>> ans = new ArrayList<>();
for (int i = 0; i < n; ++i) {
for (int j = i + 1; j < n; ++j) {
if (check(i, j, words[j].length(), words[i].length(), prefix, suffix)) {
ans.add(Arrays.asList(i, j));
}
if (check(j, i, words[i].length(), words[j].length(), prefix, suffix)) {
ans.add(Arrays.asList(j, i));
}
}
}
return ans;
}
private boolean check(int i, int j, int n, int m, long[] prefix, long[] suffix) {
long t = ((prefix[i] * MUL[n]) % MOD + prefix[j]) % MOD;
long s = ((suffix[j] * MUL[m]) % MOD + suffix[i]) % MOD;
return t == s;
}
}
class Trie {
Trie[] children = new Trie[26];
Integer v;
void insert(String w, int i) {
Trie node = this;
for (char c : w.toCharArray()) {
c -= 'a';
if (node.children[c] == null) {
node.children[c] = new Trie();
}
node = node.children[c];
}
node.v = i;
}
Integer search(String w, int i, int j) {
Trie node = this;
for (int k = j; k >= i; --k) {
int idx = w.charAt(k) - 'a';
if (node.children[idx] == null) {
return null;
}
node = node.children[idx];
}
return node.v;
}
}
class Solution {
public List<List<Integer>> palindromePairs(String[] words) {
Trie trie = new Trie();
int n = words.length;
for (int i = 0; i < n; ++i) {
trie.insert(words[i], i);
}
List<List<Integer>> ans = new ArrayList<>();
for (int i = 0; i < n; ++i) {
String w = words[i];
int m = w.length();
for (int j = 0; j <= m; ++j) {
if (isPalindrome(w, j, m - 1)) {
Integer k = trie.search(w, 0, j - 1);
if (k != null && k != i) {
ans.add(Arrays.asList(i, k));
}
}
if (j != 0 && isPalindrome(w, 0, j - 1)) {
Integer k = trie.search(w, j, m - 1);
if (k != null && k != i) {
ans.add(Arrays.asList(k, i));
}
}
}
}
return ans;
}
// TLE
// private boolean isPalindrome(String w, int i, int j) {
// for (; i < j; ++i, --j) {
// if (w.charAt(i) != w.charAt(j)) {
// return false;
// }
// }
// return true;
// }
private boolean isPalindrome(String w, int start, int end) {
int i = start, j = end;
for (; i < j; ++i, --j) {
if (w.charAt(i) != w.charAt(j)) {
return false;
}
}
return true;
}
}
func palindromePairs(words []string) [][]int {
base := 131
mod := int(1e9) + 7
mul := make([]int, 310)
mul[0] = 1
for i := 1; i < len(mul); i++ {
mul[i] = (mul[i-1] * base) % mod
}
n := len(words)
prefix := make([]int, n)
suffix := make([]int, n)
for i, word := range words {
m := len(word)
for j, c := range word {
t := int(c-'a') + 1
s := int(word[m-j-1]-'a') + 1
prefix[i] = (prefix[i]*base)%mod + t
suffix[i] = (suffix[i]*base)%mod + s
}
}
check := func(i, j, n, m int) bool {
t := ((prefix[i]*mul[n])%mod + prefix[j]) % mod
s := ((suffix[j]*mul[m])%mod + suffix[i]) % mod
return t == s
}
var ans [][]int
for i := 0; i < n; i++ {
for j := i + 1; j < n; j++ {
if check(i, j, len(words[j]), len(words[i])) {
ans = append(ans, []int{i, j})
}
if check(j, i, len(words[i]), len(words[j])) {
ans = append(ans, []int{j, i})
}
}
}
return ans
}