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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值