DSA Trie

Palindrome Pairs

Find all index pairs (i, j) such that words[i] + words[j] is a palindrome — hash-map prefix/suffix trick.

Hard
Time O(N * L^2) Space O(N * L)
LeetCode
7 min read
trie hash-map strings

Problem#

Given a list of unique words, return all pairs of distinct indices (i, j) such that the concatenation words[i] + words[j] is a palindrome.

Examples#

  • words = ["abcd","dcba","lls","s","sssll"][[0,1],[1,0],[3,2],[2,4]].
  • words = ["bat","tab","cat"][[0,1],[1,0]].

Constraints#

  • 1 <= words.length <= 5000, 0 <= words[i].length <= 300.

Hints#

Hint 1
If words[i] + words[j] is a palindrome, splitting at some point gives A + B where one side is a palindrome and the other side equals the reverse of the other word.
Hint 2
Index every word’s reverse. For each word, split at every point and look up the reverse of the non-palindromic side.

Approach#

Build a hash map of reversed(word) -> index. For each word, iterate split positions k = 0..len. Let left = word[0..k) and right = word[k..len). If right is palindromic, look up left in the map (some word equals reverse(left) and appended after word completes the palindrome). Symmetrically: if left is palindromic, look up right (some word equals reverse(right) prepended).

Solution#

Palindrome Pairs
class Solution {
bool isPal(const string& s, int l, int r) {
while (l < r) if (s[l++] != s[r--]) return false;
return true;
}
public:
vector<vector<int>> palindromePairs(vector<string>& words) {
unordered_map<string, int> idx;
for (int i = 0; i < (int)words.size(); ++i) {
string r = words[i];
reverse(r.begin(), r.end());
idx[r] = i;
}
set<pair<int,int>> dedupe;
for (int i = 0; i < (int)words.size(); ++i) {
const string& w = words[i];
int n = w.size();
for (int k = 0; k <= n; ++k) {
// Case A: left palindrome -> look up right.
if (isPal(w, 0, k - 1)) {
string suff = w.substr(k);
auto it = idx.find(suff);
if (it != idx.end() && it->second != i) dedupe.insert({it->second, i});
}
// Case B: right palindrome -> look up left.
if (k != n && isPal(w, k, n - 1)) {
string pref = w.substr(0, k);
auto it = idx.find(pref);
if (it != idx.end() && it->second != i) dedupe.insert({i, it->second});
}
}
}
return {dedupe.begin(), dedupe.end()};
}
};

Editorial#

Every palindromic concatenation splits at exactly one point into “palindrome half plus reverse-match half”. Iterating splits covers all cases including empty strings (the empty string is a palindrome, so it pairs with every palindromic word in both orders). The set dedupes the case where both halves are palindromic and both cases A/B insert the same pair.

Complexity#

  • Time: O(N * L^2) — N words, L splits each, each split’s palindrome check is O(L).
  • Space: O(N * L) for the reverse map.

Concept revision#

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.