336. 回文对(Trie树,manacher)

 方法一:枚举前后缀,使用HashMap

class Solution {
    public List<List<Integer>> palindromePairs(String[] words) {
        List<List<Integer>> res = new ArrayList<>();
        int n = words.length;
        if(n < 2) return res;
        Map<String,Integer> map = new HashMap<>();
        for(int i = 0; i < n; i++) {
            map.put(words[i],i);
        }
        for(String word : words) {
            int index = map.get(word);
            for(int i = 0; i <= word.length(); i++) {
                String prefix = word.substring(0,i);
                String suffix = word.substring(i);
                String rPrefix = new StringBuilder(prefix).reverse().toString();
                String rSuffix = new StringBuilder(suffix).reverse().toString();
                if(prefix.equals(rPrefix)) {
                    if(map.containsKey(rSuffix) && !rSuffix.equals(word)) {
                        res.add(Arrays.asList(map.get(rSuffix),index));
                    }
                }
                    //空字符串只算一次!
                if(i != word.length() && suffix.equals(rSuffix)) {
                    if(map.containsKey(rPrefix) && !rPrefix.equals(word)) {
                        res.add(Arrays.asList(index,map.get(rPrefix)));
                    }
                }
            }
        }
        return res;
    }
}

方法二:使用manacher来枚举前后缀

class Solution {
    public List<List<Integer>> palindromePairs(String[] words) {
        List<List<Integer>> res = new ArrayList<>();
        int n = words.length;
        Map<String,Integer> map = new HashMap<>();
        for(int i = 0; i < n; i++) {
            map.put(words[i],i);
        }

        for(int i = 0; i < n; i++) {
            res.addAll(findAll(words[i],i,map));
        }
        return res;
    }
    public List<List<Integer>> findAll(String s, int index, Map<String,Integer> map) {
        List<List<Integer>> res = new ArrayList<>();
        int[] r = manacher(s);
        String reverse = new StringBuilder(s).reverse().toString();
        Integer rest = map.get("");
        if(rest != null && rest != index && reverse.equals(s)) {
            res.add(Arrays.asList(rest,index));
            res.add(Arrays.asList(index,rest));
        }
        int mid = r.length >> 1;
        for(int i = 1; i < mid; i++) {
            if(i - r[i] == -1) {
                rest = map.get(reverse.substring(0,mid-i));
                if(rest != null && rest != index) {
                    res.add(Arrays.asList(rest,index));
                }
            }
        }
        for(int i = mid + 1; i <  r.length; i++) {
            if(i + r[i] ==  r.length) {
                rest = map.get(reverse.substring((mid<<1)-i));
                if(rest != null && rest != index) {
                    res.add(Arrays.asList(index,rest));
                }
            }
        }
        return res;
    }
    public int[] manacher(String s) {
        char[] arr = manacherString(s);
        int[] r = new int[arr.length];
        int R = -1, C = -1;
        for(int i = 0; i < r.length; i++) {
            r[i] = R > i ? Math.min(R - i, r[2 * C - i]) : 1;
            while(i + r[i] < arr.length && i - r[i] > - 1) {
                if(arr[i+r[i]] == arr[i-r[i]]) {
                    r[i]++;
                } else {
                    break;
                }
            }
            if(i + r[i] > R) {
                R = i + r[i];
                C = i;
            }
        }
        return r;
    }
    
    public char[] manacherString(String s) {
        char[] arrs = s.toCharArray();
        char[] res = new char[s.length() * 2 + 1];
        int index = 0;
        for(int i = 0; i < res.length; i++) {
            res[i] = i % 2 == 0 ? '$' : arrs[index++];
        }
        return res;
    }
}

方法三:Trie树

class Solution {
    private Node root;
    public List<List<Integer>> palindromePairs(String[] words) {
        this.root = new Node();
        int n = words.length;
        // 字典树的插入,注意维护每个节点上的两个列表
        for (int i = 0; i < n; i++) {
            String rev = new StringBuilder(words[i]).reverse().toString();
            Node cur = root;
            if (isPalindrome(rev.substring(0))) cur.suffixs.add(i);
            for (int j = 0; j < rev.length(); j++) {
                char ch = rev.charAt(j);
                if (cur.children[ch-'a']==null) cur.children[ch-'a'] = new Node();
                cur = cur.children[ch-'a'];
                if (isPalindrome(rev.substring(j+1))) cur.suffixs.add(i);
            }
            cur.words.add(i);
        }
        // 用以存放答案的列表
        List<List<Integer>> ans = new ArrayList<>();
        
        for (int i = 0; i < n; i++) {
            String word = words[i];
            Node cur = root;
            int j = 0;
            for ( ;j < word.length(); j++) {
                // 到j位置,后续字符串若是回文对,则在该节点位置上所有单词都可以与words[i]构成回文对
                // 因为我们插入的时候是用每个单词的逆序插入的:)
                if(isPalindrome(word.substring(j))) 
                    for (int k : cur.words) 
                        if (k != i) ans.add(Arrays.asList(i,k));
                
                char ch = word.charAt(j);
                if (cur.children[ch-'a'] == null) break;
                cur = cur.children[ch-'a'];

            }
            // words[i]遍历完了,现在找所有大于words[i]长度且符合要求的单词,suffixs列表就派上用场了:)
            if (j == word.length()) 
                for (int k : cur.suffixs) 
                    if (k != i) ans.add(Arrays.asList(i,k));
            
        }
        return ans;
        
    }
    //  判断一个字符串是否是回文字符串
    private boolean isPalindrome(String w) {
        int i = 0, j = w.length()-1;
        while (i < j) {
            if (w.charAt(i) != w.charAt(j)) return false;
            i++; j--;
        }
        return true;
    }
}
class Node {
    public Node[] children;
    public List<Integer> words;
    public List<Integer> suffixs;
    public Node() {
        this.children = new Node[26];
        this.words = new ArrayList<>();
        this.suffixs = new ArrayList<>();
    }
}
原文地址:https://www.cnblogs.com/yonezu/p/13446693.html