LeetCode 336: 回文对
题目描述
给定一组 互不相同 的单词, 找出所有不同 的索引对(i, j),使得列表中的两个单词, words[i] + words[j] ,可拼接成回文串。
示例 1:
输入:[“abcd”,“dcba”,“lls”,“s”,“sssll”]
输出:[[0,1],[1,0],[3,2],[2,4]]
解释:可拼接成的回文串为 [“dcbaabcd”,“abcddcba”,“slls”,“llssssll”]
示例 2:
输入:[“bat”,“tab”,“cat”]
输出:[[0,1],[1,0]]
解释:可拼接成的回文串为 [“battab”,“tabbat”]
解题
先简化一下题目难度,如果是一组大小相同但互不相同的单词,找出所有索引对,满足words[i] + words[j] ,可拼接成回文串,那很容易,不管是哈希表还是前缀树都能很好地解决。但问题在于,能拼成回文串的两个单词的长度可能不是相同的。不过即使两个单词长度不相同,可以看作两个相同单词拆分后的结果,那么较长的单词包含一个回文子串以及能与较短单词组成回文串的部分。
因此对于每一个单词,我们可以做如下处理:
1. 对当前单词进行拆分,并判断拆分的两部分是否是回文子串。
2. 如果前半部分是回文子串,则在单词组中找与后半部分组成回文串的单词,如果存在一个非己单词,那么将该索引对存入结果;如果后半部分是回文串,则在单词数组中找与前半部分组成回文串的单词,如果存在一个非己单词,那么将该索引对保存到数组中,注意这两种情况对应的索引对顺序不同!
现在问题转化为:
1. 如何进行单词查找?哈希表或者前缀树。
2. 找到对应单词后,如何确定索引? 关联容器或者前缀树。
以下是基于前缀树的解法:
class Solution {
public:
vector<vector<int>> palindromePairs(vector<string>& words) {
vector<vector<int>> out;
root = new nNode;
for (int i=0; i < words.size(); ++i)
insert(words[i], i);
int char_num, index;
for (int i=0; i < words.size(); ++i){
char_num = words[i].size()-1;
for (int j=0, k=char_num; j <= words[i].size(); ++j,--k){
if (j && isPal(words[i], 0, j-1)){
index = findPal(words[i], j, char_num);
if (index>=0 && index!=i) out.push_back({index, i});
}
if (isPal(words[i], j, char_num)){
index = findPal(words[i], 0, j-1);
if (index>=0 && index!=i) out.push_back({i, index});
}
}
}
return out;
}
private:
struct nNode {
nNode *childs[26] = {NULL};
bool is_word = false;
int index = -1;
} *root;
void insert(const string &word, int index){
if (word.size()==0) {
root->is_word = true;
root->index = index;
}
nNode *cur_node = root;
for (int i= word.size()-1; i >= 0; --i){
int cur_index = word[i]-'a';
if (cur_node->childs[cur_index]==NULL)
cur_node->childs[cur_index] = new nNode;
cur_node = cur_node->childs[cur_index];
}
cur_node->is_word = true;
cur_node->index = index;
}
bool isPal(const string &word, int l, int r){
while (l < r){
if (word[l++]!=word[r--]) return false;
}
return true;
}
int findPal(const string &word, int l, int r){
nNode *cur_node = root;
int index;
while (l <= r){
index = word[l]-'a';
if (cur_node->childs[index]==NULL) return -1;
cur_node = cur_node->childs[index];
++l;
}
if (cur_node->is_word) return cur_node->index;
return -1;
}
};