Implement Magic Dictionary — Solution in Python, Java & C++
Implement Magic Dictionary solution explained: step-by-step approach, complexity and code in Python, Java, C++ and JavaScript. A medium problem.
Implement Magic Dictionary is a medium coding problem on strings, hash table and depth-first search, asked in Amazon and Google interviews.
- Difficulty: Medium
- Topics: Strings, Hash Table, Depth-First Search, Trie
- Asked at: Amazon, Google
- Time limit: 2 s
- Memory limit: 256 MB
- Languages: JavaScript, TypeScript, Python, Java, C++, C, C#, Go, Kotlin, Swift, Rust, PHP and Ruby
Problem statement
Design a dictionary that answers: can you change exactly one character of a given word so that it becomes a word in the dictionary? Write the class MagicDictionary:
MagicDictionary()creates the object.void buildDict(String[] dictionary)fills it with a list of distinct words.boolean search(String searchWord)returnstrueif changing exactly one character ofsearchWord(to a different letter) turns it into a dictionary word,falseotherwise.
A word that is already in the dictionary does not count by itself — one character must change.
The judge calls the methods in the order listed in the first input line, with the arguments in the second; the expected output holds each call's result, null for the constructor and for every void method.
Example 1
Input: ["MagicDictionary","buildDict","search","search","search","search"]
[[],[["hello","leetcode"]],["hello"],["hhllo"],["hell"],["leetcoded"]]
Output: [null,null,false,true,false,false]
Explanation: "hello" itself needs zero changes, so it is false. "hhllo" becomes "hello" by changing its second letter. Lengths must match, so "hell" and "leetcoded" can never work.
Example 2
Input: ["MagicDictionary","buildDict","search","search","search"]
[[],[["hello","hallo","a"]],["hello"],["b"],["hxllx"]]
Output: [null,null,true,true,false]
Explanation: "hello" is in the dictionary, but changing its 'e' to 'a' gives "hallo", which is too — so it is true. "b" → "a" works; "hxllx" differs from "hello" in two places.
Constraints
1 <= dictionary.length <= 1001 <= dictionary[i].length <= 100dictionary[i] consists of only lowercase English lettersAll the strings in dictionary are distinct1 <= searchWord.length <= 100searchWord consists of only lowercase English lettersbuildDict is called once, before searchAt most 100 calls are made to search
Hints for Implement Magic Dictionary
Hint 1
A dictionary word can only be reached if it has the same length as the search word.
Hint 2
For a candidate of the same length, count the positions where the two words differ.
Hint 3
The answer is
trueexactly when some same-length word differs in exactly one position; stop counting a candidate as soon as it reaches two differences.
How to solve Implement Magic Dictionary
Changing exactly one character of searchWord gives word w precisely when w has the same length and differs from searchWord in exactly one position. With at most 100 words of length at most 100, checking each same-length word directly is fast; grouping the words by length skips the others.
Approach
buildDict: group the words by length.search(s): for each wordwof length|s|, count positionsiwithw[i] != s[i], stopping at 2.- Return
trueas soon as some word has exactly one difference;falseif none does.
Why it works
Changing one character to a different letter produces a word at Hamming distance exactly 1 from the original, and every word at distance 1 can be produced that way. So the question is whether the dictionary holds a word at Hamming distance 1 — which the scan checks word by word.
Complexity
- Time —
O(N · L) per search for N words of length L; O(N · L) to build - Space —
O(N · L)
Pitfalls
- A search word that is itself in the dictionary is not automatically true — it needs a different word one change away.
- Words of a different length can never match; checking them wastes time and risks index errors.
- For far more searches, precompute every "generalised neighbour" (
h*llo, one*per position) with its count — the standard O(L²) per search alternative.
Reference solution
Python
from typing import List
class MagicDictionary:
def __init__(self):
self.by_len = {}
def buildDict(self, dictionary: List[str]) -> None:
for w in dictionary:
self.by_len.setdefault(len(w), []).append(w)
def search(self, searchWord: str) -> bool:
for w in self.by_len.get(len(searchWord), []):
diff = 0
for a, b in zip(w, searchWord):
if a != b:
diff += 1
if diff > 1:
break
if diff == 1:
return True
return FalseJava
class MagicDictionary {
private Map<Integer, List<String>> byLen = new HashMap<>();
public MagicDictionary() {
}
public void buildDict(String[] dictionary) {
for (String w : dictionary) byLen.computeIfAbsent(w.length(), k -> new ArrayList<>()).add(w);
}
public boolean search(String searchWord) {
for (String w : byLen.getOrDefault(searchWord.length(), Collections.emptyList())) {
int diff = 0;
for (int k = 0; k < w.length() && diff < 2; k++) if (w.charAt(k) != searchWord.charAt(k)) diff++;
if (diff == 1) return true;
}
return false;
}
}C++
class MagicDictionary {
unordered_map<int, vector<string>> byLen;
public:
MagicDictionary() {}
void buildDict(vector<string> dictionary) {
for (auto& w : dictionary) byLen[w.size()].push_back(w);
}
bool search(string searchWord) {
auto it = byLen.find(searchWord.size());
if (it == byLen.end()) return false;
for (auto& w : it->second) {
int diff = 0;
for (size_t k = 0; k < w.size() && diff < 2; k++) if (w[k] != searchWord[k]) diff++;
if (diff == 1) return true;
}
return false;
}
};JavaScript
var MagicDictionary = function() {
this.byLen = {};
};
MagicDictionary.prototype.buildDict = function(dictionary) {
for (var i = 0; i < dictionary.length; i++) {
var w = dictionary[i];
(this.byLen[w.length] = this.byLen[w.length] || []).push(w);
}
};
MagicDictionary.prototype.search = function(searchWord) {
var words = this.byLen[searchWord.length] || [];
for (var i = 0; i < words.length; i++) {
var diff = 0;
for (var k = 0; k < searchWord.length && diff < 2; k++) if (words[i][k] !== searchWord[k]) diff++;
if (diff === 1) return true;
}
return false;
};Also on the editorial tab: C, C#, Go, Kotlin, PHP, Ruby, Rust, Swift, TypeScript.
All 515 strings problems · the whole catalogue
Learn the technique: Strings · Hashing: Hash Maps and Hash Sets