LeetCode 336. Palindrome Pairs(回文对)

Posted jmspan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 336. Palindrome Pairs(回文对)相关的知识,希望对你有一定的参考价值。

原题网址:https://leetcode.com/problems/palindrome-pairs/

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"]

方法:通过Trie来发现对称的单词。

public class Solution 
    private boolean palindrome(char[] word, int i, int j) 
        while (i<j) if (word[i++] != word[j--]) return false;
        return true;
    
    public List<List<Integer>> palindromePairs(String[] words) 
        List<List<Integer>> pairs = new ArrayList<>();
        if (words == null || words.length == 0) return pairs;
        char[][] was = new char[words.length][];
        TrieNode root = new TrieNode();
        for(int i=0; i<words.length; i++) 
            was[i] = words[i].toCharArray();
            TrieNode node = root;
            for(int j=0; j<was[i].length; j++) node = node.next(was[i][j]);
            node.id = i;
        
        if (root.id != -1) 
            for(int i=0; i<was.length; i++) 
                if (i != root.id && palindrome(was[i], 0, was[i].length-1)) 
                    Integer[] pair = new Integer[2];
                    pair[0] = root.id;
                    pair[1] = i;
                    pairs.add(Arrays.asList(pair));
                    pair = new Integer[2];
                    pair[0] = i;
                    pair[1] = root.id;
                    pairs.add(Arrays.asList(pair));
                
            
        
        for(int i=0; i<was.length; i++) 
            if (was[i].length == 0) continue;
            TrieNode node = root;
            
            for(int j=was[i].length-1; j>=0; j--) 
                node = node.nexts[was[i][j]-'a'];
                if (node == null) break;
                // System.out.printf("i=%d, j=%d, words[%d]=%s, node.id=%d, palindrome=%b\\n", i, j, i, words[i], node.id, palindrome(was[i], 0, j-1));
                if (node.id == -1 || node.id == i || !palindrome(was[i], 0, j-1)) continue;
                Integer[] pair = new Integer[2];
                pair[0] = node.id;
                pair[1] = i;
                pairs.add(Arrays.asList(pair));
            
            if (node != null) 
                LinkedList<TrieNode> queue = new LinkedList<>();
                queue.add(node);
                while (!queue.isEmpty()) 
                    TrieNode trie = queue.remove();
                    if (trie.id != -1 && trie.id != i && was[trie.id].length != 0 && was[trie.id].length != was[i].length
                    && palindrome(was[trie.id], was[i].length, was[trie.id].length-1)) 
                        Integer[] pair = new Integer[2];
                        pair[0] = trie.id;
                        pair[1] = i;
                        pairs.add(Arrays.asList(pair));
                    
                    for(int j=0; j<trie.size; j++) queue.add(trie.nexts[trie.trans[j]]);
                
            
        
        return pairs;
    

class TrieNode 
    int id = -1;
    TrieNode[] nexts = new TrieNode[26];
    char[] trans = new char[26];
    int size = 0;
    TrieNode next(char ch) 
        char id = (char)(ch-'a');
        if (nexts[id] == null) 
            trans[size++] = id;
            nexts[id] = new TrieNode();
        
        return nexts[id];
    


另一个实现方式:

public class Solution 
    public List<List<Integer>> palindromePairs(String[] words) 
        Trie root = new Trie();
        char[][] was = new char[words.length][];
        for(int i=0; i<words.length; i++) 
            was[i] = words[i].toCharArray();
            Trie node = root;
            for(int j=0; j<was[i].length; j++) node = node.append(was[i][j]);
            node.w = i;
        
        List<List<Integer>> results = new ArrayList<>();
        if (root.w != -1) 
            for(int i=0; i<was.length; i++) 
                if (i==root.w) continue;
                int left = 0, right = was[i].length-1;
                for(; left < right && was[i][left] == was[i][right]; left ++, right --);
                if (left >= right) 
                    Integer[] pair = new Integer[2];
                    pair[0] = root.w;
                    pair[1] = i;
                    // System.out.printf("1 root.w=%d, i=%d, pair=[%d, %d]\\n", root.w, i, pair[0], pair[1]);
                    results.add(Arrays.asList(pair));
                    pair = new Integer[2];
                    pair[0] = i;
                    pair[1] = root.w;
                    // System.out.printf("2 root.w=%d, i=%d, pair=[%d, %d]\\n", root.w, i, pair[0], pair[1]);
                    results.add(Arrays.asList(pair));
                
            
        
        for(int i=0; i<was.length; i++) 
            Trie node = root;
            for(int j=was[i].length-1; j>=0; j--) 
                node = node.nexts[was[i][j]-'a'];
                if (node == null) break;
                if (node.w != -1 && node.w != i) 
                    int left = 0, right = was[i].length-was[node.w].length-1;
                    for(; left < right && was[i][left] == was[i][right]; left ++, right --);
                    if (left >= right) 
                        Integer[] pair = new Integer[2];
                        pair[0] = node.w;
                        pair[1] = i;
                        // System.out.printf("3 node.w=%d, i=%d, pair=[%d, %d]\\n", node.w, i, pair[0], pair[1]);
                        results.add(Arrays.asList(pair));
                    
                
            
            if (node != root && node != null) 
                LinkedList<Trie> queue = new LinkedList<>();
                for(int j=0; j<node.size; j++) queue.add(node.nexts[node.letters[j]-'a']);
                while (!queue.isEmpty()) 
                    Trie q = queue.remove();
                    if (q.w != -1 && q.w != i) 
                        int left = was[i].length, right = was[q.w].length-1;
                        for(; left < right && was[q.w][left] == was[q.w][right]; left ++, right --);
                        if (left >= right) 
                            Integer[] pair = new Integer[2];
                            pair[0] = q.w;
                            pair[1] = i;
                            // System.out.printf("4 q.w=%d, i=%d, pair=[%d, %d]\\n", q.w, i, pair[0], pair[1]);
                            results.add(Arrays.asList(pair));
                        
                    
                    for(int j=0; j<q.size; j++) queue.add(q.nexts[q.letters[j]-'a']);
                
            
        
        return results;
    

class Trie 
    int w = -1;
    char[] letters = new char[26];
    int size;
    Trie[] nexts = new Trie[26];
    Trie append(char ch) 
        if (nexts[ch-'a'] != null) return nexts[ch-'a'];
        letters[size++] = ch;
        nexts[ch-'a'] = new Trie();
        return nexts[ch-'a'];
    

如果不想使用广度优先,则可以建立前缀树和后缀树,分别检查。

public class Solution 
    public List<List<Integer>> palindromePairs(String[] words) 
        List<List<Integer>> results = new ArrayList<>();
        Trie forward = new Trie();
        Trie reverse = new Trie();
        char[][] was = new char[words.length][];
        
        for(int i = 0; i < words.length; i++) 
            was[i] = words[i].toCharArray();
            Trie f = forward;
            for(int j = 0; j < was[i].length; j++) 
                f = f.append(was[i][j]);
            
            f.id = i;
            Trie r = reverse;
            for(int j = was[i].length - 1; j >= 0; j--) 
                r = r.append(was[i][j]);
            
            r.id = i;
        
        
        for(int i = 0; i < words.length; i++) 
            Trie f = forward;
            int j = was[i].length - 1;
            for(; j >= 0 && f != null; j--) 
                if (f.id != -1 && f.id != i) 
                    int left = 0, right = j;
                    for(; left < right && was[i][left] == was[i][right]; left++, right--);
                    if (left >= right) 
                        Integer[] result = new Integer[2];
                        result[0] = f.id;
                        result[1] = i;
                        results.add(Arrays.asList(result));
                    
                
                f = f.nexts[was[i][j] - 'a'];
            
            if (j < 0 && f != null && f.id != -1 && f.id < i) 
                Integer[] result = new Integer[2];
                result[0] = f.id;
                result[1] = i;
                results.add(Arrays.asList(result));
                result = new Integer[2];
                result[0] = i;
                result[1] = f.id;
                results.add(Arrays.asList(result));
                            
            
            Trie r = reverse;
            j = 0;
            for(; j < was[i].length && r != null; j++) 
                if (r.id != -1 && r.id != i) 
                    int left = j, right = was[i].length - 1;
                    for(; left < right && was[i][left] == was[i][right]; left++, right--);
                    if (left >= right) 
                        Integer[] result = new Integer[2];
                        result[0] = i;
                        result[1] = r.id;
                        results.add(Arrays.asList(result));
                    
                
                r = r.nexts[was[i][j] - 'a'];
            
            // 引起重复
            // if (j == was[i].length && r != null && r.id != -1 && i != r.id) 
            //     Integer[] result = new Integer[2];
            //     result[0] = i;
            //     result[1] = r.id;
            //     results.add(Arrays.asList(result));
            // 
        
        return results;
    


class Trie 
    int id = -1;
    Trie[] nexts = new Trie[26];
    Trie append(char ch) 
        if (nexts[ch - 'a'] == null) nexts[ch - 'a'] = new Trie();
        return nexts[ch - 'a'];
    

注意当两个字符串长度相等、字符顺序相反的时候,如何去除重复。

另一种方法是不使用Trie,而是按照长度穷举切分方法,参考:https://leetcode.com/discuss/93603/150-ms-45-lines-java-solution

以上是关于LeetCode 336. Palindrome Pairs(回文对)的主要内容,如果未能解决你的问题,请参考以下文章

leetcode No336. Palindrome Pairs

leetcode No336. Palindrome Pairs

[Leetcode] 336. Palindrome Pairs_Hard

leetcode336. Palindrome Pairs

LeetCodePalindrome Pairs(336)

336. Palindrome Pairs