方法一:枚举前后缀,使用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<>(); } }