From 0a83a3faf13fc9d1440a5849d79a35872e5926f4 Mon Sep 17 00:00:00 2001 From: Yang Libin Date: Fri, 17 Nov 2023 09:05:59 +0000 Subject: [PATCH] feat: add solutions to lc problem: No.0288 No.0288.Unique Word Abbreviation --- .../0288.Unique Word Abbreviation/README.md | 120 +++++++++++------- .../README_EN.md | 120 ++++++++++++------ .../Solution.cpp | 18 ++- .../0288.Unique Word Abbreviation/Solution.go | 27 ++-- .../Solution.java | 15 +-- .../0288.Unique Word Abbreviation/Solution.py | 16 +-- .../0288.Unique Word Abbreviation/Solution.ts | 29 +++++ 7 files changed, 218 insertions(+), 127 deletions(-) create mode 100644 solution/0200-0299/0288.Unique Word Abbreviation/Solution.ts diff --git a/solution/0200-0299/0288.Unique Word Abbreviation/README.md b/solution/0200-0299/0288.Unique Word Abbreviation/README.md index 14b08b1c1e959..02b5f688444a4 100644 --- a/solution/0200-0299/0288.Unique Word Abbreviation/README.md +++ b/solution/0200-0299/0288.Unique Word Abbreviation/README.md @@ -67,7 +67,15 @@ validWordAbbr.isUnique("cake"); // 返回 true,因为 "cake" 已经存在于 -哈希表实现,其中 key 存放单词缩写,value 存放单词缩写所对应的所有单词的集合。 +**方法一:哈希表** + +根据题目描述,我们定义一个函数 $abbr(s)$,它的功能是计算单词 $s$ 的缩写。如果单词 $s$ 的长度小于 $3$,那么它的缩写就是它本身;否则,它的缩写是它的首字母 + (它的长度 - 2) + 它的尾字母。 + +接下来,我们定义一个哈希表 $d$,它的键是单词的缩写,值是一个集合,集合中的元素是所有缩写为该键的单词。我们遍历给定的单词字典,对于字典中的每个单词 $s$,我们求出它的缩写 $abbr(s)$,并将 $s$ 添加到 $d[abbr(s)]$ 中。 + +在判断单词 $word$ 是否满足题目要求时,我们求出它的缩写 $abbr(word)$,如果 $abbr(word)$ 不在哈希表 $d$ 中,那么 $word$ 满足题目要求;否则,我们判断 $d[abbr(word)]$ 中是否只有一个元素,如果 $d[abbr(word)]$ 中只有一个元素且该元素就是 $word$,那么 $word$ 满足题目要求。 + +时间复杂度方面,初始化哈希表的时间复杂度是 $O(n)$,其中 $n$ 是单词字典的长度;判断单词是否满足题目要求的时间复杂度是 $O(1)$。空间复杂度方面,哈希表的空间复杂度是 $O(n)$。 @@ -78,18 +86,16 @@ validWordAbbr.isUnique("cake"); // 返回 true,因为 "cake" 已经存在于 ```python class ValidWordAbbr: def __init__(self, dictionary: List[str]): - self.words = defaultdict(set) - for word in dictionary: - abbr = self.word_abbr(word) - self.words[abbr].add(word) + self.d = defaultdict(set) + for s in dictionary: + self.d[self.abbr(s)].add(s) def isUnique(self, word: str) -> bool: - abbr = self.word_abbr(word) - words = self.words[abbr] - return not words or (len(words) == 1 and word in words) + s = self.abbr(word) + return s not in self.d or all(word == t for t in self.d[s]) - def word_abbr(self, s): - return s if len(s) < 3 else f'{s[0]}{len(s) - 2}{s[-1]}' + def abbr(self, s: str) -> str: + return s if len(s) < 3 else s[0] + str(len(s) - 2) + s[-1] # Your ValidWordAbbr object will be instantiated and called as such: @@ -103,25 +109,22 @@ class ValidWordAbbr: ```java class ValidWordAbbr { - private Map> words; + private Map> d = new HashMap<>(); public ValidWordAbbr(String[] dictionary) { - words = new HashMap<>(); - for (String word : dictionary) { - String abbr = abbr(word); - words.computeIfAbsent(abbr, k -> new HashSet<>()).add(word); + for (var s : dictionary) { + d.computeIfAbsent(abbr(s), k -> new HashSet<>()).add(s); } } public boolean isUnique(String word) { - String abbr = abbr(word); - Set vals = words.get(abbr); - return vals == null || (vals.size() == 1 && vals.contains(word)); + var ws = d.get(abbr(word)); + return ws == null || (ws.size() == 1 && ws.contains(word)); } private String abbr(String s) { int n = s.length(); - return n < 3 ? s : s.charAt(0) + Integer.toString(n - 2) + s.charAt(n - 1); + return n < 3 ? s : s.substring(0, 1) + (n - 2) + s.substring(n - 1); } } @@ -137,23 +140,21 @@ class ValidWordAbbr { ```cpp class ValidWordAbbr { public: - unordered_map> words; - ValidWordAbbr(vector& dictionary) { - for (auto word : dictionary) { - auto abbr = wordAbbr(word); - words[abbr].insert(word); + for (auto& s : dictionary) { + d[abbr(s)].insert(s); } } bool isUnique(string word) { - auto abbr = wordAbbr(word); - if (!words.count(abbr)) return true; - auto vals = words[abbr]; - return vals.size() == 1 && vals.count(word); + string s = abbr(word); + return !d.count(s) || (d[s].size() == 1 && d[s].count(word)); } - string wordAbbr(string s) { +private: + unordered_map> d; + + string abbr(string& s) { int n = s.size(); return n < 3 ? s : s.substr(0, 1) + to_string(n - 2) + s.substr(n - 1, 1); } @@ -170,33 +171,32 @@ public: ```go type ValidWordAbbr struct { - words map[string]map[string]bool + d map[string]map[string]bool } func Constructor(dictionary []string) ValidWordAbbr { - words := make(map[string]map[string]bool) - for _, word := range dictionary { - abbr := wordAbbr(word) - if words[abbr] == nil { - words[abbr] = make(map[string]bool) + d := make(map[string]map[string]bool) + for _, s := range dictionary { + abbr := abbr(s) + if _, ok := d[abbr]; !ok { + d[abbr] = make(map[string]bool) } - words[abbr][word] = true + d[abbr][s] = true } - return ValidWordAbbr{words} + return ValidWordAbbr{d} } func (this *ValidWordAbbr) IsUnique(word string) bool { - abbr := wordAbbr(word) - words := this.words[abbr] - return words == nil || (len(words) == 1 && words[word]) + ws := this.d[abbr(word)] + return ws == nil || (len(ws) == 1 && ws[word]) } -func wordAbbr(s string) string { +func abbr(s string) string { n := len(s) - if n <= 2 { + if n < 3 { return s } - return s[0:1] + strconv.Itoa(n-2) + s[n-1:] + return fmt.Sprintf("%c%d%c", s[0], n-2, s[n-1]) } /** @@ -206,6 +206,40 @@ func wordAbbr(s string) string { */ ``` +### **TypeScript** + +```ts +class ValidWordAbbr { + private d: Map> = new Map(); + + constructor(dictionary: string[]) { + for (const s of dictionary) { + const abbr = this.abbr(s); + if (!this.d.has(abbr)) { + this.d.set(abbr, new Set()); + } + this.d.get(abbr)!.add(s); + } + } + + isUnique(word: string): boolean { + const ws = this.d.get(this.abbr(word)); + return ws === undefined || (ws.size === 1 && ws.has(word)); + } + + abbr(s: string): string { + const n = s.length; + return n < 3 ? s : s[0] + (n - 2) + s[n - 1]; + } +} + +/** + * Your ValidWordAbbr object will be instantiated and called as such: + * var obj = new ValidWordAbbr(dictionary) + * var param_1 = obj.isUnique(word) + */ +``` + ### **...** ``` diff --git a/solution/0200-0299/0288.Unique Word Abbreviation/README_EN.md b/solution/0200-0299/0288.Unique Word Abbreviation/README_EN.md index 5f525ec1de7c5..2ebeb06cf1a71 100644 --- a/solution/0200-0299/0288.Unique Word Abbreviation/README_EN.md +++ b/solution/0200-0299/0288.Unique Word Abbreviation/README_EN.md @@ -59,6 +59,16 @@ validWordAbbr.isUnique("cake"); // return true, because "cake&quo ## Solutions +**Solution 1: Hash Table** + +According to the problem description, we define a function $abbr(s)$, which calculates the abbreviation of the word $s$. If the length of the word $s$ is less than $3$, then its abbreviation is itself; otherwise, its abbreviation is its first letter + (its length - 2) + its last letter. + +Next, we define a hash table $d$, where the key is the abbreviation of the word, and the value is a set, the elements of which are all words abbreviated as that key. We traverse the given word dictionary, and for each word $s$ in the dictionary, we calculate its abbreviation $abbr(s)$, and add $s$ to $d[abbr(s)]$. + +When judging whether the word $word$ meets the requirements of the problem, we calculate its abbreviation $abbr(word)$. If $abbr(word)$ is not in the hash table $d$, then $word$ meets the requirements of the problem; otherwise, we judge whether there is only one element in $d[abbr(word)]$. If there is only one element in $d[abbr(word)]$ and that element is $word$, then $word$ meets the requirements of the problem. + +In terms of time complexity, the time complexity of initializing the hash table is $O(n)$, where $n$ is the length of the word dictionary; the time complexity of judging whether a word meets the requirements of the problem is $O(1)$. In terms of space complexity, the space complexity of the hash table is $O(n)$. + ### **Python3** @@ -66,18 +76,16 @@ validWordAbbr.isUnique("cake"); // return true, because "cake&quo ```python class ValidWordAbbr: def __init__(self, dictionary: List[str]): - self.words = defaultdict(set) - for word in dictionary: - abbr = self.word_abbr(word) - self.words[abbr].add(word) + self.d = defaultdict(set) + for s in dictionary: + self.d[self.abbr(s)].add(s) def isUnique(self, word: str) -> bool: - abbr = self.word_abbr(word) - words = self.words[abbr] - return not words or (len(words) == 1 and word in words) + s = self.abbr(word) + return s not in self.d or all(word == t for t in self.d[s]) - def word_abbr(self, s): - return s if len(s) < 3 else f'{s[0]}{len(s) - 2}{s[-1]}' + def abbr(self, s: str) -> str: + return s if len(s) < 3 else s[0] + str(len(s) - 2) + s[-1] # Your ValidWordAbbr object will be instantiated and called as such: @@ -89,25 +97,22 @@ class ValidWordAbbr: ```java class ValidWordAbbr { - private Map> words; + private Map> d = new HashMap<>(); public ValidWordAbbr(String[] dictionary) { - words = new HashMap<>(); - for (String word : dictionary) { - String abbr = abbr(word); - words.computeIfAbsent(abbr, k -> new HashSet<>()).add(word); + for (var s : dictionary) { + d.computeIfAbsent(abbr(s), k -> new HashSet<>()).add(s); } } public boolean isUnique(String word) { - String abbr = abbr(word); - Set vals = words.get(abbr); - return vals == null || (vals.size() == 1 && vals.contains(word)); + var ws = d.get(abbr(word)); + return ws == null || (ws.size() == 1 && ws.contains(word)); } private String abbr(String s) { int n = s.length(); - return n < 3 ? s : s.charAt(0) + Integer.toString(n - 2) + s.charAt(n - 1); + return n < 3 ? s : s.substring(0, 1) + (n - 2) + s.substring(n - 1); } } @@ -123,23 +128,21 @@ class ValidWordAbbr { ```cpp class ValidWordAbbr { public: - unordered_map> words; - ValidWordAbbr(vector& dictionary) { - for (auto word : dictionary) { - auto abbr = wordAbbr(word); - words[abbr].insert(word); + for (auto& s : dictionary) { + d[abbr(s)].insert(s); } } bool isUnique(string word) { - auto abbr = wordAbbr(word); - if (!words.count(abbr)) return true; - auto vals = words[abbr]; - return vals.size() == 1 && vals.count(word); + string s = abbr(word); + return !d.count(s) || (d[s].size() == 1 && d[s].count(word)); } - string wordAbbr(string s) { +private: + unordered_map> d; + + string abbr(string& s) { int n = s.size(); return n < 3 ? s : s.substr(0, 1) + to_string(n - 2) + s.substr(n - 1, 1); } @@ -156,33 +159,32 @@ public: ```go type ValidWordAbbr struct { - words map[string]map[string]bool + d map[string]map[string]bool } func Constructor(dictionary []string) ValidWordAbbr { - words := make(map[string]map[string]bool) - for _, word := range dictionary { - abbr := wordAbbr(word) - if words[abbr] == nil { - words[abbr] = make(map[string]bool) + d := make(map[string]map[string]bool) + for _, s := range dictionary { + abbr := abbr(s) + if _, ok := d[abbr]; !ok { + d[abbr] = make(map[string]bool) } - words[abbr][word] = true + d[abbr][s] = true } - return ValidWordAbbr{words} + return ValidWordAbbr{d} } func (this *ValidWordAbbr) IsUnique(word string) bool { - abbr := wordAbbr(word) - words := this.words[abbr] - return words == nil || (len(words) == 1 && words[word]) + ws := this.d[abbr(word)] + return ws == nil || (len(ws) == 1 && ws[word]) } -func wordAbbr(s string) string { +func abbr(s string) string { n := len(s) - if n <= 2 { + if n < 3 { return s } - return s[0:1] + strconv.Itoa(n-2) + s[n-1:] + return fmt.Sprintf("%c%d%c", s[0], n-2, s[n-1]) } /** @@ -192,6 +194,40 @@ func wordAbbr(s string) string { */ ``` +### **TypeScript** + +```ts +class ValidWordAbbr { + private d: Map> = new Map(); + + constructor(dictionary: string[]) { + for (const s of dictionary) { + const abbr = this.abbr(s); + if (!this.d.has(abbr)) { + this.d.set(abbr, new Set()); + } + this.d.get(abbr)!.add(s); + } + } + + isUnique(word: string): boolean { + const ws = this.d.get(this.abbr(word)); + return ws === undefined || (ws.size === 1 && ws.has(word)); + } + + abbr(s: string): string { + const n = s.length; + return n < 3 ? s : s[0] + (n - 2) + s[n - 1]; + } +} + +/** + * Your ValidWordAbbr object will be instantiated and called as such: + * var obj = new ValidWordAbbr(dictionary) + * var param_1 = obj.isUnique(word) + */ +``` + ### **...** ``` diff --git a/solution/0200-0299/0288.Unique Word Abbreviation/Solution.cpp b/solution/0200-0299/0288.Unique Word Abbreviation/Solution.cpp index fe386370afe2d..725ff31309b08 100644 --- a/solution/0200-0299/0288.Unique Word Abbreviation/Solution.cpp +++ b/solution/0200-0299/0288.Unique Word Abbreviation/Solution.cpp @@ -1,22 +1,20 @@ class ValidWordAbbr { public: - unordered_map> words; - ValidWordAbbr(vector& dictionary) { - for (auto word : dictionary) { - auto abbr = wordAbbr(word); - words[abbr].insert(word); + for (auto& s : dictionary) { + d[abbr(s)].insert(s); } } bool isUnique(string word) { - auto abbr = wordAbbr(word); - if (!words.count(abbr)) return true; - auto vals = words[abbr]; - return vals.size() == 1 && vals.count(word); + string s = abbr(word); + return !d.count(s) || (d[s].size() == 1 && d[s].count(word)); } - string wordAbbr(string s) { +private: + unordered_map> d; + + string abbr(string& s) { int n = s.size(); return n < 3 ? s : s.substr(0, 1) + to_string(n - 2) + s.substr(n - 1, 1); } diff --git a/solution/0200-0299/0288.Unique Word Abbreviation/Solution.go b/solution/0200-0299/0288.Unique Word Abbreviation/Solution.go index c0dd978df04b8..aead3810a1e06 100644 --- a/solution/0200-0299/0288.Unique Word Abbreviation/Solution.go +++ b/solution/0200-0299/0288.Unique Word Abbreviation/Solution.go @@ -1,31 +1,30 @@ type ValidWordAbbr struct { - words map[string]map[string]bool + d map[string]map[string]bool } func Constructor(dictionary []string) ValidWordAbbr { - words := make(map[string]map[string]bool) - for _, word := range dictionary { - abbr := wordAbbr(word) - if words[abbr] == nil { - words[abbr] = make(map[string]bool) + d := make(map[string]map[string]bool) + for _, s := range dictionary { + abbr := abbr(s) + if _, ok := d[abbr]; !ok { + d[abbr] = make(map[string]bool) } - words[abbr][word] = true + d[abbr][s] = true } - return ValidWordAbbr{words} + return ValidWordAbbr{d} } func (this *ValidWordAbbr) IsUnique(word string) bool { - abbr := wordAbbr(word) - words := this.words[abbr] - return words == nil || (len(words) == 1 && words[word]) + ws := this.d[abbr(word)] + return ws == nil || (len(ws) == 1 && ws[word]) } -func wordAbbr(s string) string { +func abbr(s string) string { n := len(s) - if n <= 2 { + if n < 3 { return s } - return s[0:1] + strconv.Itoa(n-2) + s[n-1:] + return fmt.Sprintf("%c%d%c", s[0], n-2, s[n-1]) } /** diff --git a/solution/0200-0299/0288.Unique Word Abbreviation/Solution.java b/solution/0200-0299/0288.Unique Word Abbreviation/Solution.java index a7e6d9e6d6bf2..12ab7b649a5ea 100644 --- a/solution/0200-0299/0288.Unique Word Abbreviation/Solution.java +++ b/solution/0200-0299/0288.Unique Word Abbreviation/Solution.java @@ -1,23 +1,20 @@ class ValidWordAbbr { - private Map> words; + private Map> d = new HashMap<>(); public ValidWordAbbr(String[] dictionary) { - words = new HashMap<>(); - for (String word : dictionary) { - String abbr = abbr(word); - words.computeIfAbsent(abbr, k -> new HashSet<>()).add(word); + for (var s : dictionary) { + d.computeIfAbsent(abbr(s), k -> new HashSet<>()).add(s); } } public boolean isUnique(String word) { - String abbr = abbr(word); - Set vals = words.get(abbr); - return vals == null || (vals.size() == 1 && vals.contains(word)); + var ws = d.get(abbr(word)); + return ws == null || (ws.size() == 1 && ws.contains(word)); } private String abbr(String s) { int n = s.length(); - return n < 3 ? s : s.charAt(0) + Integer.toString(n - 2) + s.charAt(n - 1); + return n < 3 ? s : s.substring(0, 1) + (n - 2) + s.substring(n - 1); } } diff --git a/solution/0200-0299/0288.Unique Word Abbreviation/Solution.py b/solution/0200-0299/0288.Unique Word Abbreviation/Solution.py index ecbdd843df96a..0de1b4ffa3c88 100644 --- a/solution/0200-0299/0288.Unique Word Abbreviation/Solution.py +++ b/solution/0200-0299/0288.Unique Word Abbreviation/Solution.py @@ -1,17 +1,15 @@ class ValidWordAbbr: def __init__(self, dictionary: List[str]): - self.words = defaultdict(set) - for word in dictionary: - abbr = self.word_abbr(word) - self.words[abbr].add(word) + self.d = defaultdict(set) + for s in dictionary: + self.d[self.abbr(s)].add(s) def isUnique(self, word: str) -> bool: - abbr = self.word_abbr(word) - words = self.words[abbr] - return not words or (len(words) == 1 and word in words) + s = self.abbr(word) + return s not in self.d or all(word == t for t in self.d[s]) - def word_abbr(self, s): - return s if len(s) < 3 else f'{s[0]}{len(s) - 2}{s[-1]}' + def abbr(self, s: str) -> str: + return s if len(s) < 3 else s[0] + str(len(s) - 2) + s[-1] # Your ValidWordAbbr object will be instantiated and called as such: diff --git a/solution/0200-0299/0288.Unique Word Abbreviation/Solution.ts b/solution/0200-0299/0288.Unique Word Abbreviation/Solution.ts new file mode 100644 index 0000000000000..53c853e9da464 --- /dev/null +++ b/solution/0200-0299/0288.Unique Word Abbreviation/Solution.ts @@ -0,0 +1,29 @@ +class ValidWordAbbr { + private d: Map> = new Map(); + + constructor(dictionary: string[]) { + for (const s of dictionary) { + const abbr = this.abbr(s); + if (!this.d.has(abbr)) { + this.d.set(abbr, new Set()); + } + this.d.get(abbr)!.add(s); + } + } + + isUnique(word: string): boolean { + const ws = this.d.get(this.abbr(word)); + return ws === undefined || (ws.size === 1 && ws.has(word)); + } + + abbr(s: string): string { + const n = s.length; + return n < 3 ? s : s[0] + (n - 2) + s[n - 1]; + } +} + +/** + * Your ValidWordAbbr object will be instantiated and called as such: + * var obj = new ValidWordAbbr(dictionary) + * var param_1 = obj.isUnique(word) + */