zoukankan      html  css  js  c++  java
  • 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<>();
        }
    }
  • 相关阅读:
    R.java文件介绍
    Windows CE Notification API的使用方法
    Vue.js组件的重要选项
    Vue.js如何划分组件
    细数那些年我用过的前端开发工具
    前端几个常用简单的开发手册拿走不谢
    Bootstrap相关优质项目学习清单
    前端页面实现报警器提示音效果
    人工智能面试题86问,新手找工作必备!
    人工智能面试题86问,新手找工作必备!
  • 原文地址:https://www.cnblogs.com/yonezu/p/13446693.html
Copyright © 2011-2022 走看看