288. Unique Word Abbreviation
On LeetCode ->Problem¶
Implement ValidWordAbbr(dictionary) and isUnique(word).
Abbreviate words longer than two characters as first letter + number of middle characters + last letter; shorter words remain unchanged. A query is unique if no different dictionary word has its abbreviation. Duplicate dictionary entries do not matter.
dictionary = ["deer", "door", "cake", "cake"]
abbreviations = {"d2r": {"deer", "door"}, "c2e": {"cake"}}
isUnique("deer") -> False # Collides with "door".
isUnique("cake") -> True # Repeated identical words are allowed.
isUnique("cart") -> True # "c2t" is absent.
class ValidWordAbbr:
def __init__(self, dictionary: list[str]):
pass
def isUnique(self, word: str) -> bool:
pass
Key trick¶
Map each abbreviation to its sole distinct word, or None if multiple distinct words share it.
Trap¶
Dictionary membership alone does not imply uniqueness, duplicates are not collisions, and words of length one or two stay unchanged.
Why is it interesting?¶
It turns a repeated dictionary search into a constant-time lookup by storing exactly the information each query needs.
Python solution¶
class ValidWordAbbr:
def __init__(self, dictionary: list[str]):
# Each abbreviation maps to one word, or None for a collision.
self.abbrevs = {}
for word in dictionary:
abbr = self._abbrev(word)
if abbr not in self.abbrevs:
self.abbrevs[abbr] = word
elif self.abbrevs[abbr] != word:
self.abbrevs[abbr] = None
def _abbrev(self, word: str) -> str:
if len(word) <= 2:
return word
return f"{word[0]}{len(word) - 2}{word[-1]}"
def isUnique(self, word: str) -> bool:
# An absent abbreviation or an identical sole owner is valid.
return self.abbrevs.get(self._abbrev(word), word) == word
With word lengths bounded by 20 and \(n\) dictionary entries:
- Initialization: expected \(O(n)\) time.
- Query: expected \(O(1)\) time.
- Auxiliary space: \(O(n)\).
Comment on my solution¶
isUniqueis missingself; calling it as an instance method raisesTypeError.- Storing lists incorrectly rejects duplicates: with two copies of
"cake", your method returnsFalsefor"cake". - Your abbreviation logic correctly handles one-character words, but checking
len(word) <= 2is clearer. len(word[1:-1])creates an unnecessary slice; uselen(word) - 2for longer words.
# WRONG
class ValidWordAbbr:
def __init__(self, dictionary: list[str]):
self.abbrevs = {}
for s in dictionary:
abbrev = self._abbrev(s)
self.abbrevs.setdefault(abbrev, []).append(s)
def _abbrev(self, word: str):
cnt_midle = len(word[1:-1])
midle = str(cnt_midle) if cnt_midle else ""
end = "" if len(word) == 1 else word[len(word) - 1]
return word[0] + midle + end
def isUnique(word: str):
abbrev = self._abbrev(word)
if abbrev not in self.abbrevs:
return True
if len(self.abbrevs[abbrev]) == 1 and self.abbrevs[abbrev][0] == word:
return True
return False
Extra¶
Problem description¶
The abbreviation of a word is a concatenation of its first letter, the number of characters between the first and last letter, and its last letter. If a word has only two characters, then it is an abbreviation of itself.
For example:
dog --> d1gbecause there is one letter between the first letter'd'and the last letter'g'.internationalization --> i18nbecause there are 18 letters between the first letter'i'and the last letter'n'.it --> itbecause any word with only two characters is an abbreviation of itself.
Implement the ValidWordAbbr class:
ValidWordAbbr(String[] dictionary)Initializes the object with adictionaryof words.boolean isUnique(string word)Returnstrueif either of the following conditions are met (otherwise returnsfalse):- There is no word in
dictionarywhose abbreviation is equal toword's abbreviation. - For any word in
dictionarywhose abbreviation is equal toword's abbreviation, that word andwordare the same.
- There is no word in
Example 1:
Input
["ValidWordAbbr", "isUnique", "isUnique", "isUnique", "isUnique", "isUnique"]
[[["deer", "door", "cake", "card"]], ["dear"], ["cart"], ["cane"], ["make"], ["cake"]]
Output
[null, false, true, false, true, true]
Explanation
ValidWordAbbr validWordAbbr = new ValidWordAbbr(["deer", "door", "cake", "card"]);
validWordAbbr.isUnique("dear"); // return false, dictionary word "deer" and word "dear" have the same abbreviation "d2r" but are not the same.
validWordAbbr.isUnique("cart"); // return true, no words in the dictionary have the abbreviation "c2t".
validWordAbbr.isUnique("cane"); // return false, dictionary word "cake" and word "cane" have the same abbreviation "c2e" but are not the same.
validWordAbbr.isUnique("make"); // return true, no words in the dictionary have the abbreviation "m2e".
validWordAbbr.isUnique("cake"); // return true, because "cake" is already in the dictionary and no other word in the dictionary has "c2e" abbreviation.
Constraints:
1 <= dictionary.length <= 3 * 10^41 <= dictionary[i].length <= 20dictionary[i]consists of lowercase English letters.1 <= word.length <= 20wordconsists of lowercase English letters.- At most
5000calls will be made toisUnique.