0336. Palindrome Pairs - kumaeki/LeetCode GitHub Wiki

0336. Palindrome Pairs


Given a list of unique words, return all the pairs of the distinct indices (i, j) in the given list, so that the concatenation of the two words words[i] + words[j] is a palindrome.

Example 1:

Input: words = ["abcd","dcba","lls","s","sssll"]
Output: [[0,1],[1,0],[3,2],[2,4]]
Explanation: The palindromes are ["dcbaabcd","abcddcba","slls","llssssll"]

Example 2:

Input: words = ["bat","tab","cat"]
Output: [[0,1],[1,0]]
Explanation: The palindromes are ["battab","tabbat"]

Example 3:

Input: words = ["a",""]
Output: [[0,1],[1,0]]

Constraints:

  • 1 <= words.length <= 5000
  • 0 <= words[i].length <= 300
  • words[i] consists of lower-case English letters.

解法1

暴力算法.

class Solution {
    public List<List<Integer>> palindromePairs(String[] words) {
        List<List<Integer>> res = new ArrayList<List<Integer>>();
        for(int i = 0, n = words.length; i < n; i++){
            for(int j = 0; j < n; j++){
                if(i == j)
                    continue;
                
                if(isPP(words[i], words[j]))
                    res.add(Arrays.asList(new Integer[]{i, j}));
            }
        }
        return res;
    }
    
    private boolean isPP(String w1, String w2){
        String w = w1 + w2;
        for(int i = 0, n = w.length(); i < n/2; i++)
            if(w.charAt(i) != w.charAt(n - 1 - i))
                return false;
        return true;
    }
}

解法2

参考URL

O(n * k^2) java solution with Trie structure

class Solution {
    private static class TrieNode {
        // 保存下一个node的列表,长度为26,表示26个小写字母
        TrieNode[] next;
        // 在当前位置的word在 words中的index, 如果不是开始字符,那么值为-1
        // 在当前tree中是倒序储存, 所以是以开始字符为判断条件
        int index;
        // 保存满足以下条件的word的位置的list
        //  1.以到当前node为止的所有字符为后缀(注意, 在tree中是倒序储存)
        //  2.剩下的字符是回文
        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;
    }

    // 对所有word做预处理,存入tree中
    private void addWord(TrieNode node, String word, int index) {
        for (int i = word.length() - 1; i >= 0; i--) {
            int j = word.charAt(i) - 'a';

            if (node.next[j] == null) 
                node.next[j] = new TrieNode();

            // 如果剩下的字符串是回文,那么存入list中
            if (isPalindrome(word, 0, i)) 
                node.list.add(index);

            node = node.next[j];
        }
        
        // word的第一个字符是回文,因为只有一个字符
        node.list.add(index);
        // 当前node是第一个字符,记录在words中的位置
        node.index = index;
    }

    private void search(String[] words, int i, TrieNode root, List<List<Integer>> res) {
        // 对words[i],从位置0开始正向遍历
        for (int j = 0; j < words[i].length(); j++) {
            // 如果trieTree中搜索已经完结(index>=0表示当前node是否个word的第一个字符),
            // 并且得到的node所代表的字符串不是word本身,
            // 并且word剩下的子字符串是回文
            if (root.index >= 0 && root.index != i && isPalindrome(words[i], j, words[i].length() - 1)) 
                res.add(Arrays.asList(i, root.index));

            // 如果tree中有对应的当前字符,继续
            // 否则结束计算
            root = root.next[words[i].charAt(j) - 'a'];
            if (root == null) return;
        }

        // 当word已经计算到最后一个字符, 而在tree中有对应的node的时候,
        // node的list中代表的字符串就都可以和当前字符串组成回文
        for (int j : root.list) {
            if (i == j) continue;
            res.add(Arrays.asList(i, j));
        }
    }

    // 判断字符串中从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;
    }
}

解法3

这个比较好懂一些.

The Easy-to-unserstand JAVA Solution

public class Solution {
    public List<List<Integer>> palindromePairs(String[] words) {

        List<List<Integer>> res = new ArrayList<List<Integer>>();
        if(words == null || words.length == 0)
            return res;

        //build the map save the key-val pairs: String - idx
        HashMap<String, Integer> map = new HashMap<>();
        for(int i = 0; i < words.length; i++)
            map.put(words[i], i);

        //special cases: "" can be combine with any palindrome string
        if(map.containsKey("")){
            int blankIdx = map.get("");
            for(int i = 0; i < words.length; i++){
                if(isPalindrome(words[i])){
                    if(i == blankIdx)
                        continue;
                    res.add(Arrays.asList(blankIdx, i));
                    res.add(Arrays.asList(i, blankIdx));
                }
            }
        }

        //find all string and reverse string pairs
        for(int i = 0; i < words.length; i++){
            String cur_r = reverseStr(words[i]);
            if(map.containsKey(cur_r)){
                int found = map.get(cur_r);
                if(found == i) continue;
                res.add(Arrays.asList(i, found));
            }
        }

        //find the pair s1, s2 that 
        //case1 : s1[0:cut] is palindrome and s1[cut+1:] = reverse(s2) => (s2, s1)
        //case2 : s1[cut+1:] is palindrome and s1[0:cut] = reverse(s2) => (s1, s2)
        for(int i = 0; i < words.length; i++){
            String cur = words[i];
            for(int cut = 1; cut < cur.length(); cut++){
                if(isPalindrome(cur.substring(0, cut))){
                    String cut_r = reverseStr(cur.substring(cut));
                    if(map.containsKey(cut_r)){
                        int found = map.get(cut_r);
                        if(found == i) continue;
                        res.add(Arrays.asList(found, i));
                    }
                }
                if(isPalindrome(cur.substring(cut))){
                    String cut_r = reverseStr(cur.substring(0, cut));
                    if(map.containsKey(cut_r)){
                        int found = map.get(cut_r);
                        if(found == i) continue;
                        res.add(Arrays.asList(i, found));
                    }
                }
            }
        }

        return res;
    }

    public String reverseStr(String str){
        StringBuilder sb= new StringBuilder(str);
        return sb.reverse().toString();
    }

    public boolean isPalindrome(String s){
        int i = 0, j = s.length() - 1;
        while(i <= j){
            if(s.charAt(i++) != s.charAt(j--))
                return false;
        }
        return true;
    }
}
⚠️ **GitHub.com Fallback** ⚠️