Skip to content

feat: add solutions to lc problem: No.0288 #1976

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 77 additions & 43 deletions solution/0200-0299/0288.Unique Word Abbreviation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)$。

<!-- tabs:start -->

Expand All @@ -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:
Expand All @@ -103,25 +109,22 @@ class ValidWordAbbr:

```java
class ValidWordAbbr {
private Map<String, Set<String>> words;
private Map<String, Set<String>> 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<String> 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);
}
}

Expand All @@ -137,23 +140,21 @@ class ValidWordAbbr {
```cpp
class ValidWordAbbr {
public:
unordered_map<string, unordered_set<string>> words;

ValidWordAbbr(vector<string>& 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<string, unordered_set<string>> 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);
}
Expand All @@ -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])
}

/**
Expand All @@ -206,6 +206,40 @@ func wordAbbr(s string) string {
*/
```

### **TypeScript**

```ts
class ValidWordAbbr {
private d: Map<string, Set<string>> = 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)
*/
```

### **...**

```
Expand Down
120 changes: 78 additions & 42 deletions solution/0200-0299/0288.Unique Word Abbreviation/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,25 +59,33 @@ validWordAbbr.isUnique(&quot;cake&quot;); // return true, because &quot;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)$.

<!-- tabs:start -->

### **Python3**

```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:
Expand All @@ -89,25 +97,22 @@ class ValidWordAbbr:

```java
class ValidWordAbbr {
private Map<String, Set<String>> words;
private Map<String, Set<String>> 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<String> 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);
}
}

Expand All @@ -123,23 +128,21 @@ class ValidWordAbbr {
```cpp
class ValidWordAbbr {
public:
unordered_map<string, unordered_set<string>> words;

ValidWordAbbr(vector<string>& 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<string, unordered_set<string>> 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);
}
Expand All @@ -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])
}

/**
Expand All @@ -192,6 +194,40 @@ func wordAbbr(s string) string {
*/
```

### **TypeScript**

```ts
class ValidWordAbbr {
private d: Map<string, Set<string>> = 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)
*/
```

### **...**

```
Expand Down
Loading