336. Palindrome Pairs
Given a list of unique words, find all pairs of distinct indices (i, j)
in the given list, so that the concatenation of the two words, i.e. words[i] + words[j]
is a palindrome.
Example 1:
Input: ["abcd","dcba","lls","s","sssll"]
Output: [[0,1],[1,0],[3,2],[2,4]]
Explanation: The palindromes are ["dcbaabcd","abcddcba","slls","llssssll"]
Example 2:
Input: ["bat","tab","cat"]
Output: [[0,1],[1,0]]
Explanation: The palindromes are ["battab","tabbat"]
// Hashmap + Treeset
bool isValid(const string& s, int i, int j) {
while (i < j) {
if (s[i++] != s[j--]) return false;
}
return true;
}
vector<vector<int>> palindromePairs(vector<string>& words) {
vector<vector<int> > res;
unordered_map<string, size_t> str2idx;
set<size_t> strLen;
for (size_t i = 0; i < words.size(); ++i) {
str2idx[words[i]] = i;
strLen.insert(words[i].length());
}
for (size_t i = 0; i < words.size(); ++i) {
string tmp = words[i];
size_t len = tmp.length();
reverse(tmp.begin(), tmp.end());
if (str2idx.count(tmp) && str2idx[tmp] != i) { // avoid some palindromic words
res.push_back({i, str2idx[tmp]});
}
const auto len_it = strLen.find(len);
if (len_it == strLen.end()) continue;
for (auto it = strLen.begin(); it != len_it; ++it) {
int d = *it;
// Two cases
// (1) cur + tmp[d...len - 1]
if (isValid(tmp, 0, len - 1 - d) && str2idx.count(tmp.substr(len - d))) {
res.push_back({i, str2idx[tmp.substr(len - d)]});
}
// (1) tmp[0...d - 1] + cur
if (isValid(tmp, d, len - 1) && str2idx.count(tmp.substr(0, d))) {
res.push_back({str2idx[tmp.substr(0, d)], i});
}
}
}
return res;
}
// Hashmap
bool isValid(const string& s) {
for (size_t i = 0; i < s.size() / 2; ++i) {
if (s[i] != s[s.size() - 1 - i]) return false;
}
return true;
}
vector<vector<int>> palindromePairs(vector<string>& words) {
vector<vector<int> > res;
unordered_map<string, int> str2idx;
for (int i = 0; i < words.size(); ++i) {
str2idx[words[i]] = i;
}
for (int i = 0; i < words.size(); ++i) {
int l = 0, r = 0;
while (l <= r) {
string tmp = words[i].substr(l, r - l);
reverse(tmp.begin(), tmp.end());
if (str2idx.count(tmp) &&
str2idx[tmp] != i &&
isValid(words[i].substr((l == 0 ? r : 0), (l == 0 ? words[i].size() - r: l) ) ) ) {
if (l == 0) res.push_back({i, str2idx[tmp]});
else res.push_back({str2idx[tmp], i});
}
if (r < words[i].length()) ++r;
else ++l;
}
}
return res;
}
// Trie
class TrieNode {
public:
int idx;
vector<TrieNode*> next;
vector<int> list;
TrieNode() : idx(-1), next(26, nullptr) {}
~TrieNode() {
for (TrieNode* n : next) {
delete n;
}
list.clear();
}
};
bool isValid(const string& s, int i, int j) {
while (i < j) {
if (s[i++] != s[j--]) return false;
}
return true;
}
void addWord(TrieNode* root, const string& word, int index) {
for (int i = word.length() - 1; i >= 0; --i) {
int j = word[i] - 'a';
if (!root->next[j]) root->next[j] = new TrieNode();
if (isValid(word, 0, i)) root->list.emplace_back(index);
root = root->next[j];
}
root->list.emplace_back(index);
root->idx = index;
}
void search(const vector<string>& words, int i, TrieNode* root, vector<vector<int> >& res) {
for (int j = 0; j < words[i].length(); ++j) {
if (root->idx >= 0 && root->idx != i && isValid(words[i], j, words[i].length() - 1)) {
res.push_back({i, root->idx});
}
if (!root->next[words[i][j] - 'a']) return;
root = root->next[words[i][j] - 'a'];
}
for (int j : root->list) {
if (i == j) continue;
res.push_back({i, j});
}
}
vector<vector<int>> palindromePairs(vector<string>& words) {
vector<vector<int> > res;
TrieNode* root = new TrieNode();
int n = words.size();
for (int i = 0; i < n; ++i) addWord(root, words[i], i);
for (int i = 0; i < n; ++i) search(words, i, root, res);
delete root;
return res;
}
Last updated
Was this helpful?