# [LeetCode] Palindrome Pairs

## Problem

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:

``````Given words = ["bat", "tab", "cat"]
Return [[0, 1], [1, 0]]
The palindromes are ["battab", "tabbat"]
``````

Example 2:

``````Given words = ["abcd", "dcba", "lls", "s", "sssll"]
Return [[0, 1], [1, 0], [3, 2], [2, 4]]
The palindromes are ["dcbaabcd", "abcddcba", "slls", "llssssll"]
``````

## Note

HashMap和HashTable的区别：

HashTable不允许null作为键值，而HashMap允许一个null键和无限个null值；

Trie可以在`O(L)`（L为word.length）的时间复杂度下进行插入和查询操作；
HashMap和HashTable只能找到完全匹配的词组，而Trie可以找到有相同前缀的、有不同字符的、有缺失字符的词组。

##### 1. map.getOrDefault(str, i)
###### Method Syntax
``````public V getOrDefault(Object key,V defaultValue)
``````
###### Method Argument
Data Type Parameter Description
Object Key key the key whose associated value is to be returned
V defaultValue the default mapping of the key
###### Method Returns

The getOrDefault() method returns the value to which the specified key is mapped, or defaultValue if this map contains no mapping for the key.

##### 2. Arrays.asList(i, j)
###### Method Syntax
``````@SafeVarargs
public static <T> List<T> asList(T… a)
``````
###### Method Argument
Data Type Parameter Description
`T` `a` T – the class of the objects in the array
a – the array by which the list will be backed
###### Method Returns

The asList() method returns a list view of the specified array.

## Solution

### Using Trie

``````public class Solution {
class TrieNode {
TrieNode[] next;
int index;
List<Integer> list;
TrieNode() {
next = new TrieNode[26];
index = -1;
list = new ArrayList<>();
}
}
public List<List<Integer>> palindromePairs(String[] words) {
List<List<Integer>> res = new ArrayList<>();
TrieNode root = new TrieNode();
for (int i = 0; i < words.length; i++) addWord(root, words[i], i);
for (int i = 0; i < words.length; i++) search(words, i, root, res);
return res;
}
private void addWord(TrieNode root, String word, int index) {
for (int i = word.length() - 1; i >= 0; i--) {
if (root.next[word.charAt(i) - 'a'] == null) root.next[word.charAt(i) - 'a'] = new TrieNode();
root = root.next[word.charAt(i) - 'a'];
}
root.index = index;
}
private void search(String[] words, int i, TrieNode root, List<List<Integer>> list) {
for (int j = 0; j < words[i].length(); j++) {
if (root.index >= 0 && root.index != i && isPalindrome(words[i], j, words[i].length() - 1)) list.add(Arrays.asList(i, root.index));
root = root.next[words[i].charAt(j) - 'a'];
if (root == null) return;
}
for (int j : root.list) {
if (i == j) continue;
}
}
private boolean isPalindrome(String word, int i, int j) {
while (i < j) {
if (word.charAt(i++) != word.charAt(j--)) return false;
}
return true;
}
}

``````

### HashMap method

``````public class Solution {
public List<List<Integer>> palindromePairs(String[] words) {
List<List<Integer>> ret = new ArrayList<>();
if (words == null || words.length < 2) return ret;
Map<String, Integer> map = new HashMap<>();
for (int i=0; i<words.length; i++) map.put(words[i], i);
for (int i=0; i<words.length; i++) {
for (int j=0; j<=words[i].length(); j++) { // notice it should be "j <= words[i].length()"
String str1 = words[i].substring(0, j);
String str2 = words[i].substring(j);
if (isPalindrome(str1)) {
String str2rvs = new StringBuilder(str2).reverse().toString();
if (map.getOrDefault(str2rvs, i) != i) ret.add(Arrays.asList(map.get(str2rvs), i));
}
if (isPalindrome(str2) && str2.length() != 0) {
String str1rvs = new StringBuilder(str1).reverse().toString();
// check "str.length() != 0" to avoid duplicates
if (map.getOrDefault(str1rvs, i) != i) ret.add(Arrays.asList(i, map.get(str1rvs)));
}
}
}
return ret;
}
private boolean isPalindrome(String str) {
for (int l = 0, r = str.length() - 1; l <= r; l ++, r --)
if (str.charAt(l) != str.charAt(r)) return false;
return true;
}
}``````