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”]
O(n k^2 ) time O(n) space HashMap solution 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class Solution { public List<List<Integer>> palindromePairs(String[] words) { List<List<Integer>> result = new LinkedList<>(); if (words == null || words.length == 0 ) { return result; } HashMap<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++) { String left = words[i].substring(0 , j); String right = words[i].substring(j); if (isPalindrome(left)) { String rightRev = new StringBuilder(right).reverse().toString(); if (map.getOrDefault(rightRev, i) != i) { result.add(Arrays.asList(map.get(rightRev), i)); } } if (isPalindrome(right) && right.length() != 0 ) { String leftRev = new StringBuilder(left).reverse().toString(); if (map.getOrDefault(leftRev, i) != i) { result.add(Arrays.asList(map.get(leftRev), i)); } } } } return result; } public boolean isPalindrome (String word) { int left = 0 , right = word.length() - 1 ; while (left <= right) { if (word.charAt(left) != word.charAt(right)) { return false ; } left++; right--; } return true ; } }
O(n k^2 ) time O(26k) space Trie solution 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 public class Solution { public List<List<Integer>> palindromePairs(String[] words) { List<List<Integer>> result = new LinkedList<>(); if (words == null || words.length == 0 ) { return result; } TrieNode root = new TrieNode(); for (int i = 0 ; i < words.length; i++) { addWord(words[i], root, i); } for (int i = 0 ; i < words.length; i++) { searchWord(words[i], root, i, result); } return result; } public void addWord (String word, TrieNode root, 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(); } if (isPalindrome(word, 0 , i)) { root.list.add(index); } root = root.next[word.charAt(i) - 'a' ]; } root.index = index; root.list.add(index); } public void searchWord (String word, TrieNode root, int index, List<List<Integer>> result) { for (int i = 0 ; i < word.length(); i++) { if (root.index >= 0 && root.index != index && isPalindrome(word, i, word.length() - 1 )) { result.add(Arrays.asList(index, root.index)); } root = root.next[word.charAt(i) - 'a' ]; if (root == null ) { return ; } } for (int j : root.list) { if (j != index) { result.add(Arrays.asList(index, j)); } } } public class TrieNode { TrieNode[] next; int index; List<Integer> list; public TrieNode () { next = new TrieNode[26 ]; index = -1 ; list = new LinkedList<>(); } } public boolean isPalindrome (String word, int start, int end) { while (start < end) { if (word.charAt(start++) != word.charAt(end--)) { return false ; } } return true ; } }