[LeetCode] Palindrome Pairs

437 查看

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是synchronized,所以对于non-threaded applications,HashMap效率更高;
HashTable不允许null作为键值,而HashMap允许一个null键和无限个null值;
HashMap有一个subclass,叫LinkedHashMap,便于查询可预测的迭代顺序。

为什么Trie比HashMap效率更高

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

这道题依然选择HashMap的话

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();
            if (isPalindrome(word, 0, i)) root.list.add(index);
            root = root.next[word.charAt(i) - 'a'];
        }
        root.list.add(index);
        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;
            list.add(Arrays.asList(i, j));
        }
    }
    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;
    }
}