1. Question
Given a list of unique words, find all pairs of distinct indices(i, j)
in the given list, so that the concatenation of the two words, i.e.words[i] + words[j]
is a palindrome.
Example 1:
Givenwords
=["bat", "tab", "cat"]
Return[[0, 1], [1, 0]]
The palindromes are["battab", "tabbat"]
Example 2:
Givenwords
=["abcd", "dcba", "lls", "s", "sssll"]
Return[[0, 1], [1, 0], [3, 2], [2, 4]]
The palindromes are["dcbaabcd", "abcddcba", "slls", "llssssll"]
2. Implementation
(1) Trie
思路:
(1) 要看两个string连在一起是否回文串,那么这两个string必然满足这样的性质:一个string的前缀和另一个string的后缀相同且除去前(后)缀的剩余是回文串(包括空字符串)。
(2)为了比较不同string的前后缀,我们可以利用trie,插入时将每个word按照倒序放入trie,这样的好处是,当我们查询一个string的前缀时,可以通过trie快速的找到有没与前缀相同的后缀
(3)对于子串中存在回文串的string(包括空字符串), 比如abac中有aba这个回文子串,我们在trieNode里维护一个list,保存这种特性的word在输入数组的index
Copy class Solution {
class TrieNode {
//记录word在输入数组的index, 预设值为-1
int index;
// 保存word在输入数组的index,这种word满足条件:
// word的后缀在trie里, 剩余部分是回文串(包括空串)。比如abac, c为后缀,剩余部分aba。注意abac是倒着插入(即caba)trie的
List<Integer> list;
TrieNode[] childNode;
public TrieNode() {
index = -1;
list = new ArrayList<>();
childNode = new TrieNode[26];
}
}
class Trie {
TrieNode root;
public Trie() {
root = new TrieNode();
}
// 将Word倒序的插入Trie里
public void insert(String word, int index) {
TrieNode curNode = root;
for (int i = word.length() - 1; i >= 0; i--) {
if (isPalindrome(word, 0, i)) {
curNode.list.add(index);
}
int pos = word.charAt(i) - 'a';
if (curNode.childNode[pos] == null) {
curNode.childNode[pos] = new TrieNode();
}
curNode = curNode.childNode[pos];
}
curNode.index = index;
curNode.list.add(index);
}
public void search(String word, int index, List<List<Integer>> res) {
TrieNode curNode = root;
for (int i = 0; i < word.length(); i++) {
// curNode.index >= 0 意味着这里有输入数组里的string
// curNode.index != index 说明curNode.index对应的string和index对应的string不同
// 当word[i...word.length() - 1]是回文串时,说明curNode.index对应的string和index对应的string可以连在一起形成回文串
if (curNode.index >= 0 && curNode.index != index && isPalindrome(word, i, word.length() - 1)) {
res.add(Arrays.asList(index, curNode.index));
}
int pos = word.charAt(i) - 'a';
if (curNode.childNode[pos] == null) {
return;
}
curNode = curNode.childNode[pos];
}
// 当word在字符串中找到与它相同的string后, 查看curNode.list里的index, 这些index对应的word都是在curNode后面的substring为回文串
for (int j : curNode.list) {
if (j != index) {
res.add(Arrays.asList(index, j));
}
}
}
}
public List<List<Integer>> palindromePairs(String[] words) {
List<List<Integer>> res = new ArrayList<>();
if (words == null || words.length == 0) {
return res;
}
Trie trie = new Trie();
for (int i = 0; i < words.length; i++) {
trie.insert(words[i], i);
}
for (int i = 0; i < words.length; i++) {
trie.search(words[i], i, res);
}
return res;
}
public boolean isPalindrome(String word, int start, int end) {
while (start < end) {
if (word.charAt(start) != word.charAt(end)) {
return false;
}
++start;
--end;
}
return true;
}
}
3. Time & Space Complexity
Trie : 时间复杂度O(nL^2),n是words里的元素个数,L是words里word的平均长度。空间复杂度O(nL)