DSA Trie

Longest Common Suffix Queries

For each query string, find the word with longest common suffix — reversed-trie lookup.

Hard
Time O((W + Q) * L) Space O(W * L)
LeetCode
7 min read
trie strings

Problem#

You are given wordsContainer and wordsQuery. For each query, return the index of the container word with the longest common suffix with the query. Ties go to the shortest word; further ties go to the smallest index.

Examples#

  • wordsContainer = ["abcd","bcd","xbcd"], wordsQuery = ["cd","bcd","xyz"][1,1,1].
  • wordsContainer = ["abcdefgh","poiuygh","ghghgh"], wordsQuery = ["gh","acbfgh","acbfegh"][2,0,2].

Constraints#

  • 1 <= wordsContainer.length, wordsQuery.length <= 10^4, 1 <= word.length <= 5 * 10^3.

Hints#

Hint 1
Reverse every container word and insert into a trie — suffixes become prefixes.
Hint 2
At each trie node, remember the best container index that passes through it (shortest word, smallest index).

Approach#

Build a trie keyed on reversed container words. Each node remembers the best container index whose reversed string passes through that node (best by: shortest length, then smallest index). For each query, reverse it and walk the trie — return the best index at the deepest reachable node (or at the root if no characters match).

Solution#

Longest Common Suffix Queries
class Solution {
struct Node {
Node* child[26]{};
int bestIdx = -1;
};
public:
vector<int> stringIndices(vector<string>& wordsContainer, vector<string>& wordsQuery) {
Node* root = new Node();
auto better = [&](int a, int b) {
if (a == -1) return b;
if (b == -1) return a;
int la = wordsContainer[a].size(), lb = wordsContainer[b].size();
if (la != lb) return la < lb ? a : b;
return a < b ? a : b;
};
for (int i = 0; i < (int)wordsContainer.size(); ++i) {
Node* cur = root;
cur->bestIdx = better(cur->bestIdx, i);
const string& w = wordsContainer[i];
for (int k = w.size() - 1; k >= 0; --k) {
int idx = w[k] - 'a';
if (!cur->child[idx]) cur->child[idx] = new Node();
cur = cur->child[idx];
cur->bestIdx = better(cur->bestIdx, i);
}
}
vector<int> ans;
ans.reserve(wordsQuery.size());
for (auto& q : wordsQuery) {
Node* cur = root;
for (int k = q.size() - 1; k >= 0; --k) {
int idx = q[k] - 'a';
if (!cur->child[idx]) break;
cur = cur->child[idx];
}
ans.push_back(cur->bestIdx);
}
return ans;
}
};

Editorial#

Reversing turns the suffix problem into a prefix problem the trie handles natively. The trick is per-node tie-breaking: while inserting each container word, update bestIdx on every node it passes through, comparing by (length asc, index asc). Queries then descend as far as possible and read the best index at the deepest node.

Complexity#

  • Time: O((W + Q) * L) where L is average word length.
  • Space: O(W * L).

Concept revision#

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.