336.回文对 (Hard)*
题目描述*

标签*
字典树;哈希表;
思路 & 代码*
暴力方法就是对所有的字符串组合判断是否回文。这样肯定是超时的,需要优化,首先考虑所有满足条件的可能:
- 两个字符串镜像;
- 空串和回文串;
- 长度不同,则长字符串必定是由短字符串的反转加上一段回文组成。即对每个字符串,判断前缀或后缀是否回文,回文则将剩余的部分反转看是否在表中。
诶,发现没用字典树就做出来了。。。用字典树的话,应该是把字符串反转后建树,这样对于每个原始字符串,遍历的同时在字典树(后缀树)中查找,如果找到就分两种了,当前的长还是后缀的那个长,前者就判断剩余部分是否回文,后者就在后缀树中接着遍历找到剩余部分回文的串。后缀的回文串可以在构造字典树时填入当前节点。但这样感觉也挺慢的,每一步建树都要判断回文。
class Solution {
private:
bool isPalindrome(string& s, int l, int r) {
while(l < r) {
if(s[l] != s[r]) {
return false;
}
l++;
r--;
}
return true;
}
vector<string> allValidPrefix(string word) {
vector<string> res;
int len = word.length();
for(int i = 0; i < len; i++) {
if(isPalindrome(word, i, len - 1)) {
res.push_back(word.substr(0, i));
}
}
return res;
}
vector<string> allValidSuffix(string word) {
vector<string> res;
int len = word.length();
for(int i = 0; i < len; i++) {
if(isPalindrome(word, 0, i)) {
res.push_back(word.substr(i + 1));
}
}
return res;
}
public:
vector<vector<int>> palindromePairs(vector<string>& words) {
vector<vector<int>> res;
int n = words.size();
if(n == 0) {
return res;
}
// 因为要返回下标
unordered_map<string, int> idx;
for(int i = 0; i < n; i++) {
idx[words[i]] = i;
}
for(auto& word : words) {
int curIndex = idx[word];
string rev = word;
reverse(rev.begin(), rev.end());
if(idx.count(rev) && idx[rev] != curIndex) {
res.push_back({curIndex, idx[rev]});
}
auto prefixes = allValidPrefix(word);
for(auto prefix : prefixes) {
reverse(prefix.begin(), prefix.end());
if(idx.count(prefix)) {
res.push_back({curIndex, idx[prefix]});
}
}
auto suffixes = allValidSuffix(word);
for(auto suffix : suffixes) {
reverse(suffix.begin(), suffix.end());
if(idx.count(suffix)) {
res.push_back({idx[suffix], curIndex});
}
}
}
return res;
}
};
class TrieNode {
public:
vector<TrieNode*> next;
vector<int> suffixes;
vector<int> words;
TrieNode() : next(26, nullptr) {};
};
class Solution {
private:
bool isPalindrome(string& word, int l, int r) {
while(l < r) {
if(word[l] != word[r]) {
return false;
}
l++, r--;
}
return true;
}
public:
TrieNode* buildTrie(vector<string>& words) {
TrieNode* root = new TrieNode();
auto cur = root;
int n = words.size();
for(int i = 0; i < n; i++) {
cur = root;
string tmp = words[i];
reverse(tmp.begin(), tmp.end());
int len = tmp.length();
if(isPalindrome(tmp, 0, len - 1)) {
cur->suffixes.push_back(i);
}
for(int j = 0; j < len; j++) {
int c = tmp[j] - 'a';
if(cur->next[c] == nullptr) {
cur->next[c] = new TrieNode();
}
cur = cur->next[c];
if(isPalindrome(tmp, j + 1, len - 1)) {
cur->suffixes.push_back(i);
}
}
cur->words.push_back(i);
}
return root;
}
vector<vector<int>> palindromePairs(vector<string>& words) {
vector<vector<int>> res;
int n = words.size();
if(n == 0) {
return res;
}
TrieNode* root = buildTrie(words);
for(int i = 0; i < n; i++) {
int j = 0;
auto cur = root;
int len = words[i].length();
for(; j < len; j++) {
if(isPalindrome(words[i], j, len - 1)) {
for(auto& k : cur->words) {
if(k != i) {
res.push_back({i, k});
}
}
}
int c = words[i][j] - 'a';
if(cur->next[c] == nullptr) {
break;
}
cur = cur->next[c];
}
if(j == len) {
for(auto& k : cur->suffixes) {
if(k != i) {
res.push_back({i, k});
}
}
}
}
return res;
}
};
最后更新: July 23, 2022