Palindrome Pairs
You are given a 0-indexed array of unique strings words.
A palindrome pair is a pair of integers (i, j) such that:
0 <= i, j < words.length,
i != j, and
words[i] + words[j] (the concatenation of the two strings) is a palindrome.
Return an array of all the palindrome pairs of words.
You must write an algorithm with O(sum of words[i].length) runtime complexity.
There are multiple valid approaches but using a trie data structure is the simplest and most general option. Learning this will help with many difficult problems.
class Trie {
Integer endIndex;
Map<Character, Trie> child = new HashMap<>();
List<Integer> palindromesFromHere = new ArrayList<>();
boolean isWordNode() {
return endIndex != null;
}
}
class Solution {
private Trie buildTrie(String[] words) {
final Trie root = new Trie();
for (int i = 0, n = words.length; i < n; i++) {
final String currWord = words[i];
Trie currentTrie = root;
for (int j = 0, jn = currWord.length(); j < jn; j++) {
final int reverseIndex = jn - j - 1;
if (isPalindrome(currWord, 0, reverseIndex)) currentTrie.palindromesFromHere.add(i);
final Character currReverseChar = currWord.charAt(reverseIndex);
currentTrie = currentTrie.child.computeIfAbsent(currReverseChar, c -> new Trie());
}
currentTrie.endIndex = i;
}
return root;
}
public List<List<Integer>> palindromePairs(String[] words) {
final Trie root = buildTrie(words);
final List<List<Integer>> pairs = new ArrayList<>();
outer: for (int i = 0, n = words.length; i < n; i++) {
final String currWord = words[i];
Trie currentTrie = root;
for (int j = 0, jn = currWord.length(); j < jn; j++) {
// case 3 : When W1 is bigger than W2 and W1 ends with palindrome
if (currentTrie.isWordNode() && isPalindrome(currWord, j, jn - 1)) {
pairs.add(Arrays.asList(i, currentTrie.endIndex));
}
// move to next trie
currentTrie = currentTrie.child.get(currWord.charAt(j));
if (currentTrie == null) continue outer;
}
// case 1 : W1 and W2 are of same size and reverse of each other
if (currentTrie.isWordNode() && currentTrie.endIndex != i) {
pairs.add(Arrays.asList(i, currentTrie.endIndex));
}
// case 2 : W1 is smaller than W2 and W2 begins with palindrome
for (final Integer palindromeIndex : currentTrie.palindromesFromHere) {
pairs.add(Arrays.asList(i, palindromeIndex));
}
}
return pairs;
}
private boolean isPalindrome(String word, int fromIndex, int toIndex) {
for (int i = fromIndex, j = toIndex; i < j; i++, j--) {
if (word.charAt(i) != word.charAt(j)) return false;
}
return true;
}
}
Posted by Jamie Meyer 14 days ago