336.回文对
题解
本来暴力可破,到了115/134个用例时超过了时间限制。本题可用字典树优化暴力算法。先把各个字符串倒序插入字典树,可分三种情况。
①字典树中有当前字符串的翻转单词 符合题意
②当前字符串是回文串,那么可以查找字典树中的空字符
③普通情况 检查当前字符串前j个字符组成的字符串是不是回文串,若是则检索字典树时候存在后面部分的翻转即可。 同理可从后面开始检查,提高效率
class Solution {
public class Trie {
Trie[] next;
//end表示这目前这棵树是那一个索引单词的结尾
int end;
public Trie() {
this.next = new Trie[26];
this.end = -1;
}
//由于待会儿用到字典树的时候,是找目标串的翻转字符串,所以插入的时候,应该是倒序插入
public void insert(String s, int endNum){
char[] chars = s.toCharArray();
Trie cur = this;
for (int i = 0; i < chars.length; i++) {
int index = chars[i] - 'a';
if (cur.next[index] == null) cur.next[index] = new Trie();
cur = cur.next[index];
}
cur.end = endNum;
}
}
public List<List<Integer>> palindromePairs(String[] words) {
//构建字典树
Trie trie = new Trie();
for (int i = 0; i < words.length; i++) {
trie.insert(reverse(words[i]), i);
}
List<List<Integer>> res = new ArrayList<>();
List<Integer> temp = new ArrayList<>();
for (int i = 0; i < words.length; i++) {
String word = words[i];
//先去字典树中找整个单词的翻转作为特殊情况考虑
int index = findWord(trie, word);
if (index != -1 && index != i) {
addRes(res, i, index);
}
//还有一种特殊情况,我也是提交了没有通过才发现的,就是单词里有空字符串"",
//这意味他可以放在任何回文串的首尾
if (isPalindrome(word)) {
index = findWord(trie, "");
if (index != -1 && index != i) addRes(res, i, index);
}
for (int j = 0; j < word.length(); j++) {
String ls = word.substring(0, j + 1);
String rs = word.substring(j + 1);
//先判断前半部分[0, j]是不是回文串
if (isPalindrome(ls)) {
int pre = findWord(trie, rs);
if (pre != -1 && pre != i) addRes(res, pre, i);
}
//再判断[j + 1, end],一定要加j != word.length() - 1,要不然会和上面找整个字符串的翻转重复
if (j != word.length() - 1 && isPalindrome(rs)) {
int after = findWord(trie, ls);
if (after != -1 && after != i) addRes(res, i, after);
}
}
}
return res;
}
private void addRes(List<List<Integer>> res, int i, int j) {
List<Integer> list = new ArrayList<>();
list.add(i);
list.add(j);
res.add(list);
}
private boolean isPalindrome(String s) {
int i = 0;
int j = s.length() - 1;
char[] letters = s.toCharArray();
while (i < j) {
if (letters[i] != letters[j]) return false;
i++;
j--;
}
return true;
}
private int findWord(Trie trie, String word) {
Trie cur = trie;
char[] chars = word.toCharArray();
for (int i = 0; i < chars.length; i++) {
int temp = chars[i] - 'a';
if (cur.next[temp] == null) return -1;
else cur = cur.next[temp];
}
return cur.end;
}
private String reverse(String word) {
StringBuilder sb = new StringBuilder(word);
return sb.reverse().toString();
}
}