LeetCode Daily 14/09/2025 - 966. Vowel Spellchecker
Problem Link
LeetCode 966 - Vowel Spellchecker
Difficulty: Medium
Topic: String, Hash Table
Daily Question: 14th September 2025
Problem Recap
We need to implement a spellchecker that corrects query words based on a given wordlist. The spellchecker handles two types of spelling mistakes with specific precedence rules:
- Capitalization errors: Case-insensitive matching
- Vowel errors: Vowels (‘a’, ‘e’, ‘i’, ‘o’, ‘u’) can be interchanged
Precedence Rules (in order):
- Exact match (case-sensitive) → return the same word
- Capitalization match → return first match in wordlist
- Vowel error match → return first match in wordlist
- No match → return empty string
Intuition
This problem is essentially about efficient string matching with different levels of tolerance. The key insight is to preprocess the wordlist into different data structures to enable fast lookups:
- Exact matching: Use a set for O(1) lookups
- Case-insensitive matching: Map lowercase versions to first occurrence
- Vowel-insensitive matching: Map “devoweled” versions to first occurrence
The tricky part is handling the precedence correctly and ensuring we return the first match from the wordlist when multiple candidates exist.
Approach
Step 1: Preprocess the Wordlist
We create three data structures:
exact: Set containing all words as-is for exact matchingcase_map: Maps lowercase words to their first occurrence in wordlistvowel_map: Maps devoweled words to their first occurrence in wordlist
Step 2: Devowel Function
Create a helper function that:
- Converts word to lowercase
- Replaces all vowels with a placeholder (e.g., ‘*‘)
- This normalizes words for vowel-error matching
Step 3: Query Processing
For each query, check in precedence order:
- Is it in
exactset? → return as-is - Is its lowercase version in
case_map? → return mapped value - Is its devoweled version in
vowel_map? → return mapped value - Otherwise → return empty string
Step 4: Handle First Occurrence
When building case_map and vowel_map, use setdefault() to ensure only the first occurrence from wordlist is stored.
Complexity Analysis
- Time complexity:
- Preprocessing:
O(W * L)where W = wordlist length, L = average word length - Query processing:
O(Q * L)where Q = queries length - Total:
O((W + Q) * L)
- Preprocessing:
- Space complexity:
O(W * L)- for storing the three data structures
Solution
1 | class Solution: |
Example Walkthrough
Input: wordlist = ["KiTe","kite","hare","Hare"], queries = ["kite","Kite","KiTe","Hare","HARE","Hear","hear","keti","keet","keto"]
Preprocessing:
exact: {"KiTe", "kite", "hare", "Hare"}
case_map:
"kite"→"KiTe"(first occurrence)"hare"→"hare"(first occurrence)
vowel_map:
"k*t*"→"KiTe"(first occurrence)"h*r*"→"hare"(first occurrence)
Query Processing:
"kite"→ exact match ✅ →"kite""Kite"→ case match ("kite"in case_map) →"KiTe""KiTe"→ exact match ✅ →"KiTe""Hare"→ exact match ✅ →"Hare""HARE"→ case match ("hare"in case_map) →"hare""Hear"→ no exact, no case, devowel("Hear") ="h**r"≠"h*r*"→"""hear"→ no exact, no case, devowel("hear") ="h**r"≠"h*r*"→"""keti"→ vowel match (devowel("keti") ="k*t*") →"KiTe""keet"→ no match (devowel("keet") ="k**t"≠"k*t*") →"""keto"→ vowel match (devowel("keto") ="k*t*") →"KiTe"
Output: ["kite","KiTe","KiTe","Hare","hare","","","KiTe","","KiTe"]
Key Takeaways
- Precedence matters: Always check exact → case → vowel → none in that order
- First occurrence rule: Use
setdefault()to capture only the first match from wordlist - Efficient preprocessing: Build lookup structures once, query many times
- Vowel normalization: Replace vowels with consistent placeholder for matching
- String manipulation: Careful handling of case conversion and character replacement
This problem demonstrates the importance of strategic preprocessing and clear precedence handling in string matching algorithms.
Part of my daily LeetCode journey! Follow along for more algorithm solutions and explanations.