Vowel Spellchecker

Look up queries against a wordlist with three fallback levels — exact, case-insensitive, vowel-mask.

Medium
Time O(N + Q * L) Space O(N * L)
LeetCode
5 min read
hash-map strings

Problem#

Given wordlist and queries, for each query return the matching word using this priority: (1) exact match; (2) case-insensitive match (return first such word in wordlist); (3) vowel-error match where vowels can be replaced by any vowel (case-insensitive, return first match). Otherwise "".

Examples#

  • wordlist = ["KiTe","kite","hare","Hare"], queries = ["kite","Kite","KiTe","Hare","HARE","Hear","hear","keti","keet","keto"]["kite","KiTe","KiTe","Hare","hare","","","KiTe","","KiTe"].

Constraints#

  • 1 <= wordlist.length, queries.length <= 5000, 1 <= word.length <= 7.

Hints#

Hint 1
Three precomputed indices: set of exact words, map lowercase->first matching, map vowel-masked->first matching.
Hint 2
Mask vowels by replacing them all with * after lowercasing.

Approach#

Build three structures from wordlist (in order, only inserting the first occurrence in the maps). For each query: check exact set; else lowercase and check; else vowel-mask and check.

Solution#

Vowel Spellchecker
class Solution {
string lower(string s) { for (char& c : s) c = tolower(c); return s; }
string mask(string s) {
s = lower(std::move(s));
for (char& c : s) if (c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') c = '*';
return s;
}
public:
vector<string> spellchecker(vector<string>& wordlist, vector<string>& queries) {
unordered_set<string> exact(wordlist.begin(), wordlist.end());
unordered_map<string, string> caseMap, vowelMap;
for (auto& w : wordlist) {
string lo = lower(w);
if (!caseMap.count(lo)) caseMap[lo] = w;
string mk = mask(w);
if (!vowelMap.count(mk)) vowelMap[mk] = w;
}
vector<string> ans;
ans.reserve(queries.size());
for (auto& q : queries) {
if (exact.count(q)) { ans.push_back(q); continue; }
string lo = lower(q);
auto it = caseMap.find(lo);
if (it != caseMap.end()) { ans.push_back(it->second); continue; }
string mk = mask(q);
auto it2 = vowelMap.find(mk);
ans.push_back(it2 != vowelMap.end() ? it2->second : "");
}
return ans;
}
};

Editorial#

Building each index in wordlist order with “first wins” satisfies the spec’s tiebreaker without sorting. The three layers cascade — exact wins over case-insensitive wins over vowel-error — and each layer is O(L) per query after preprocessing.

Complexity#

  • Time: O((N + Q) * L).
  • Space: O(N * L).

Concept revision#

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.