Skip to content

Commit 4f2f6a1

Browse files
authored
feat: add solutions to lcci problems: No.10.02,10.05 (doocs#2692)
1 parent 4b2ed19 commit 4f2f6a1

File tree

22 files changed

+591
-285
lines changed

22 files changed

+591
-285
lines changed

lcci/08.03.Magic Index/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
1. 如果 $i > j$,返回 $-1$。
3838
2. 否则,我们取中间位置 $mid = (i + j) / 2$,然后递归调用 $dfs(i, mid-1)$,如果返回值不为 $-1$,说明在左半部分找到了魔术索引,直接返回。否则,如果 $nums[mid] = mid$,说明找到了魔术索引,直接返回。否则,递归调用 $dfs(mid+1, j)$ 并返回。
3939

40-
时间复杂度 $O(\log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为数组的长度
40+
时间复杂度最坏情况下为 $O(n)$,空间复杂度最坏情况下为 $O(n)$。其中 $n$ 是数组 $nums$ 的长度
4141

4242
<!-- tabs:start -->
4343

lcci/08.03.Magic Index/README_EN.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ The implementation of the function $dfs(i, j)$ is as follows:
4343
1. If $i > j$, return $-1$.
4444
2. Otherwise, we take the middle position $mid = (i + j) / 2$, then recursively call $dfs(i, mid-1)$. If the return value is not $-1$, it means that the magic index is found in the left half, return it directly. Otherwise, if $nums[mid] = mid$, it means that the magic index is found, return it directly. Otherwise, recursively call $dfs(mid+1, j)$ and return.
4545

46-
The time complexity is $O(\log n)$, and the space complexity is $O(\log n)$. Where $n$ is the length of the array.
46+
In the worst case, the time complexity is $O(n)$, and the space complexity is $O(n)$. Where $n$ is the length of the array $nums$.
4747

4848
<!-- tabs:start -->
4949

lcci/10.02.Group Anagrams/README.md

Lines changed: 128 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -28,31 +28,47 @@
2828

2929
## 解法
3030

31-
### 方法一
31+
### 方法一:哈希表
32+
33+
1. 遍历字符串,对每个字符串按照**字符字典序**排序,得到一个新的字符串。
34+
2. 以新字符串为 `key``[str]``value`,存入哈希表当中(`HashMap<String, List<String>>`)。
35+
3. 后续遍历得到相同 `key` 时,将其加入到对应的 `value` 当中即可。
36+
37+
`strs = ["eat", "tea", "tan", "ate", "nat", "bat"]` 为例,遍历结束时,哈希表的状况:
38+
39+
| key | value |
40+
| ------- | ----------------------- |
41+
| `"aet"` | `["eat", "tea", "ate"]` |
42+
| `"ant"` | `["tan", "nat"] ` |
43+
| `"abt"` | `["bat"] ` |
44+
45+
最后返回哈希表的 `value` 列表即可。
46+
47+
时间复杂度 $O(n\times k\times \log k)$。其中 $n$ 和 $k$ 分别是字符串数组的长度和字符串的最大长度。
3248

3349
<!-- tabs:start -->
3450

3551
```python
3652
class Solution:
3753
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
38-
chars = defaultdict(list)
54+
d = defaultdict(list)
3955
for s in strs:
40-
k = ''.join(sorted(list(s)))
41-
chars[k].append(s)
42-
return list(chars.values())
56+
k = ''.join(sorted(s))
57+
d[k].append(s)
58+
return list(d.values())
4359
```
4460

4561
```java
4662
class Solution {
4763
public List<List<String>> groupAnagrams(String[] strs) {
48-
Map<String, List<String>> chars = new HashMap<>();
64+
Map<String, List<String>> d = new HashMap<>();
4965
for (String s : strs) {
5066
char[] t = s.toCharArray();
5167
Arrays.sort(t);
52-
String k = new String(t);
53-
chars.computeIfAbsent(k, key -> new ArrayList<>()).add(s);
68+
String k = String.valueOf(t);
69+
d.computeIfAbsent(k, key -> new ArrayList<>()).add(s);
5470
}
55-
return new ArrayList<>(chars.values());
71+
return new ArrayList<>(d.values());
5672
}
5773
}
5874
```
@@ -61,68 +77,132 @@ class Solution {
6177
class Solution {
6278
public:
6379
vector<vector<string>> groupAnagrams(vector<string>& strs) {
64-
unordered_map<string, vector<string>> chars;
65-
for (auto s : strs) {
80+
unordered_map<string, vector<string>> d;
81+
for (auto& s : strs) {
6682
string k = s;
6783
sort(k.begin(), k.end());
68-
chars[k].emplace_back(s);
84+
d[k].emplace_back(s);
6985
}
70-
vector<vector<string>> res;
71-
for (auto it = chars.begin(); it != chars.end(); ++it) {
72-
res.emplace_back(it->second);
73-
}
74-
return res;
86+
vector<vector<string>> ans;
87+
for (auto& [_, v] : d) ans.emplace_back(v);
88+
return ans;
7589
}
7690
};
7791
```
7892
7993
```go
80-
func groupAnagrams(strs []string) [][]string {
81-
chars := map[string][]string{}
94+
func groupAnagrams(strs []string) (ans [][]string) {
95+
d := map[string][]string{}
8296
for _, s := range strs {
83-
key := []byte(s)
84-
sort.Slice(key, func(i, j int) bool {
85-
return key[i] < key[j]
86-
})
87-
chars[string(key)] = append(chars[string(key)], s)
97+
t := []byte(s)
98+
sort.Slice(t, func(i, j int) bool { return t[i] < t[j] })
99+
k := string(t)
100+
d[k] = append(d[k], s)
88101
}
89-
var res [][]string
90-
for _, v := range chars {
91-
res = append(res, v)
102+
for _, v := range d {
103+
ans = append(ans, v)
92104
}
93-
return res
105+
return
94106
}
95107
```
96108

97109
```ts
98110
function groupAnagrams(strs: string[]): string[][] {
99-
const map = new Map<string, string[]>();
111+
const d: Map<string, string[]> = new Map();
100112
for (const s of strs) {
101-
const k = s.split('').sort().join();
102-
map.set(k, (map.get(k) || []).concat([s]));
113+
const k = s.split('').sort().join('');
114+
if (!d.has(k)) {
115+
d.set(k, []);
116+
}
117+
d.get(k)!.push(s);
118+
}
119+
return Array.from(d.values());
120+
}
121+
```
122+
123+
<!-- tabs:end -->
124+
125+
### 方法二:计数
126+
127+
我们也可以将方法一中的排序部分改为计数,也就是说,将每个字符串 $s$ 中的字符以及出现的次数作为 `key`,将字符串 $s$ 作为 `value` 存入哈希表当中。
128+
129+
时间复杂度 $O(n\times (k + C))$。其中 $n$ 和 $k$ 分别是字符串数组的长度和字符串的最大长度,而 $C$ 是字符集的大小,本题中 $C = 26$。
130+
131+
<!-- tabs:start -->
132+
133+
```python
134+
class Solution:
135+
def groupAnagrams(self, strs: List[str]) -> List[List[str]]:
136+
d = defaultdict(list)
137+
for s in strs:
138+
cnt = [0] * 26
139+
for c in s:
140+
cnt[ord(c) - ord('a')] += 1
141+
d[tuple(cnt)].append(s)
142+
return list(d.values())
143+
```
144+
145+
```java
146+
class Solution {
147+
public List<List<String>> groupAnagrams(String[] strs) {
148+
Map<String, List<String>> d = new HashMap<>();
149+
for (String s : strs) {
150+
int[] cnt = new int[26];
151+
for (int i = 0; i < s.length(); ++i) {
152+
++cnt[s.charAt(i) - 'a'];
153+
}
154+
StringBuilder sb = new StringBuilder();
155+
for (int i = 0; i < 26; ++i) {
156+
if (cnt[i] > 0) {
157+
sb.append((char) ('a' + i)).append(cnt[i]);
158+
}
159+
}
160+
String k = sb.toString();
161+
d.computeIfAbsent(k, key -> new ArrayList<>()).add(s);
162+
}
163+
return new ArrayList<>(d.values());
103164
}
104-
return [...map.values()];
105165
}
106166
```
107167

108-
```rust
109-
use std::collections::HashMap;
110-
111-
impl Solution {
112-
pub fn group_anagrams(strs: Vec<String>) -> Vec<Vec<String>> {
113-
let mut map = HashMap::new();
114-
for s in strs {
115-
let key = {
116-
let mut cs = s.chars().collect::<Vec<char>>();
117-
cs.sort();
118-
cs.iter().collect::<String>()
119-
};
120-
map.entry(key)
121-
.or_insert(vec![])
122-
.push(s);
168+
```cpp
169+
class Solution {
170+
public:
171+
vector<vector<string>> groupAnagrams(vector<string>& strs) {
172+
unordered_map<string, vector<string>> d;
173+
for (auto& s : strs) {
174+
int cnt[26] = {0};
175+
for (auto& c : s) ++cnt[c - 'a'];
176+
string k;
177+
for (int i = 0; i < 26; ++i) {
178+
if (cnt[i]) {
179+
k += 'a' + i;
180+
k += to_string(cnt[i]);
181+
}
182+
}
183+
d[k].emplace_back(s);
123184
}
124-
map.into_values().collect()
185+
vector<vector<string>> ans;
186+
for (auto& [_, v] : d) ans.emplace_back(v);
187+
return ans;
125188
}
189+
};
190+
```
191+
192+
```go
193+
func groupAnagrams(strs []string) (ans [][]string) {
194+
d := map[[26]int][]string{}
195+
for _, s := range strs {
196+
cnt := [26]int{}
197+
for _, c := range s {
198+
cnt[c-'a']++
199+
}
200+
d[cnt] = append(d[cnt], s)
201+
}
202+
for _, v := range d {
203+
ans = append(ans, v)
204+
}
205+
return
126206
}
127207
```
128208

0 commit comments

Comments
 (0)