给定一组唯一的单词, 找出所有不同 的索引对(i, j),使得列表中的两个单词, words[i] + words[j] ,可拼接成回文串。
示例 1:
输入: ["abcd","dcba","lls","s","sssll"]
输出: [[0,1],[1,0],[3,2],[2,4]]
解释: 可拼接成的回文串为 ["dcbaabcd","abcddcba","slls","llssssll"]
示例 2:
输入: ["bat","tab","cat"]
输出: [[0,1],[1,0]]
解释: 可拼接成的回文串为 ["battab","tabbat"]
思路:我是纯字典树过的,再次刷这道题时参考了官方题解,通过马拉车优化回文串查找。
class Solution {
class trie {
class node {
int[] c = new int[26];
int flag;
public node() {
flag = -1;
}
}
List<node> tree = new ArrayList<>();
public trie() {
tree.add(new node());
}
public void insert(String s, int id) {
int len = s.length(), add = 0;
for (int i = 0; i < len; i++) {
int x = s.charAt(i) - 'a';
if (tree.get(add).c[x] == 0) {
tree.add(new node());
tree.get(add).c[x] = tree.size() - 1;
}
add = tree.get(add).c[x];
}
tree.get(add).flag = id;
}
public int[] query(String s) {
int len = s.length(), add = 0;
int[] ret = new int[len + 1];
Arrays.fill(ret, -1);
for (int i = 0; i < len; i++) {
ret[i] = tree.get(add).flag;
int x = s.charAt(i) - 'a';
if (tree.get(add).c[x] == 0)
return ret;
add = tree.get(add).c[x];
}
ret[len] = tree.get(add).flag;
return ret;
}
}
public List<List<Integer>> palindromePairs(String[] words) {
trie trie1 = new trie();
trie trie2 = new trie();
int n = words.length;
for (int i = 0; i < n; i++) {
trie1.insert(words[i], i);
StringBuilder str = new StringBuilder(words[i]);
str.reverse();
trie2.insert(str.toString(), i);
}
List<List<Integer>> ret = new ArrayList<>();
for (int i = 0; i < n; i++) {
int[][] rec = manacher(words[i]);
int[] id1 = trie2.query(words[i]);
words[i] = new StringBuilder(words[i]).reverse().toString();
int[] id2 = trie1.query(words[i]);
int m = words[i].length();
int allid = id1[m];
if (allid != -1 && allid != i)
ret.add(Arrays.asList(i, allid));
for (int j = 0; j < m; j++) {
if (rec[j][0] != 0) {
int leftid = id2[m - j - 1];
if (leftid != -1 && leftid != i)
ret.add(Arrays.asList(leftid, i));
}
if (rec[j][1] != 0) {
int rightid = id1[j];
if (rightid != -1 && rightid != i)
ret.add(Arrays.asList(i, rightid));
}
}
}
return ret;
}
public int[][] manacher(String s) {
int n = s.length();
StringBuilder tmp = new StringBuilder("#");
for (int i = 0; i < n; i++) {
if (i > 0) tmp.append('*');
tmp.append(s.charAt(i));
}
tmp.append('!');
int m = n * 2;
int[] len = new int[m];
int[][] ret = new int[n][2];
int p = 0, maxn = -1;
for (int i = 1; i < m; i++) {
len[i] = maxn >= i ? Math.min(len[2 * p - i], maxn - i) : 0;
while (tmp.charAt(i - len[i] - 1) == tmp.charAt(i + len[i] + 1))
len[i]++;
if (i + len[i] > maxn) {
p = i;
maxn = i + len[i];
}
if (i - len[i] == 1) ret[(i + len[i]) / 2][0] = 1;
if (i + len[i] == m - 1) ret[(i - len[i]) / 2][1] = 1;
}
return ret;
}
}