Skip to content

Commit 468d402

Browse files
authored
feat: update solutions to lcof problems (doocs#2883)
1 parent a5b2ad7 commit 468d402

File tree

12 files changed

+45
-33
lines changed

12 files changed

+45
-33
lines changed

lcof/面试题41. 数据流中的中位数/README.md

+5-1
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,11 @@ public class MedianFinder {
418418

419419
<!-- solution:start-->
420420

421-
### 方法二
421+
### 方法二:有序列表
422+
423+
我们也可以使用一个有序列表来维护数据流中的元素,这样我们就可以直接通过索引来获取中位数。
424+
425+
时间复杂度方面,添加元素的时间复杂度为 $O(\log n)$,查找中位数的时间复杂度为 $O(1)$。空间复杂度为 $O(n)$。其中 $n$ 为数据流中元素的个数。
422426

423427
<!-- tabs:start -->
424428

lcof/面试题42. 连续子数组的最大和/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ $$
6565

6666
我们可以不用开一个数组来存储所有的计算结果,而是只用两个变量 $f$ 和 $ans$ 来维护对于每一个位置 $i$ 我们的最大值,这样我们可以省去空间复杂度的开销。
6767

68-
时间复杂度 $O(n)$,空间复杂度 $O(1)$。其中 $n$ 为数组长度
68+
时间复杂度 $O(n)$,其中 $n$ 为数组长度。空间复杂度 $O(1)$。
6969

7070
<!-- tabs:start -->
7171

lcof/面试题45. 把数组排成最小的数/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9
4949

5050
### 方法一:自定义排序
5151

52-
将数组中的数字转换为字符串,然后按照字符串拼接的大小进行排序。具体地,比较两个字符串 $a$ 和 $b$,如果 $a + b \lt b + a$,则 $a$ 小于 $b$,否则 $a$ 大于 $b$。
52+
我们将数组中的数字转换为字符串,然后按照字符串拼接的大小进行排序。具体地,比较两个字符串 $a$ 和 $b$,如果 $a + b \lt b + a$,则 $a$ 小于 $b$,否则 $a$ 大于 $b$。
5353

5454
时间复杂度 $O(n \times \log n + n \times m)$,空间复杂度 $O(n \times m)$。其中 $n $ 和 $m$ 分别为数组的长度和字符串的平均长度。
5555

lcof/面试题47. 礼物的最大价值/README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,6 @@ $$
5454

5555
时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为棋盘的行数和列数。
5656

57-
我们注意到 $f[i][j]$ 只与 $f[i-1][j]$ 和 $f[i][j-1]$ 有关,因此我们可以仅用两行数组 $f[2][n+1]$ 来存储状态,从而将空间复杂度优化到 $O(n)$。
58-
5957
<!-- tabs:start -->
6058

6159
#### Python3
@@ -206,7 +204,9 @@ public class Solution {
206204

207205
<!-- solution:start-->
208206

209-
### 方法二
207+
### 方法二:动态规划(空间优化)
208+
209+
我们注意到 $f[i][j]$ 只与 $f[i-1][j]$ 和 $f[i][j-1]$ 有关,因此我们可以仅用两行数组 $f[2][n+1]$ 来存储状态,从而将空间复杂度优化到 $O(n)$。
210210

211211
<!-- tabs:start -->
212212

lcof/面试题48. 最长不含重复字符的子字符串/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9
5858

5959
我们用双指针 $j$ 和 $i$ 分别表示子串的左右边界,其中 $j$ 是滑动窗口的左边界,$i$ 是滑动窗口的右边界,用哈希表 $vis$ 记录每个字符是否出现过。
6060

61-
遍历字符串 $s$,如果此时 $s[i]$ 在哈希表 $vis$ 中存在,说明 $s[i]$ 重复了,我们需要将左边界 $j$ 右移,直到 $s[i]$ 不在哈希表 $vis$ 中为止,然后将 $s[i]$ 加入哈希表 $vis$ 中。此时,我们更新无重复字符子串的最大长度,即 $ans = max(ans, i - j + 1)$。
61+
遍历字符串 $s$,如果此时 $s[i]$ 在哈希表 $vis$ 中存在,说明 $s[i]$ 重复了,我们需要将左边界 $j$ 右移,直到 $s[i]$ 不在哈希表 $vis$ 中为止,然后将 $s[i]$ 加入哈希表 $vis$ 中。此时,我们更新无重复字符子串的最大长度,即 $ans = \max(ans, i - j + 1)$。
6262

6363
遍历结束后,我们返回 $ans$ 即可。
6464

lcof/面试题49. 丑数/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ public class Solution {
245245

246246
### 方法二:动态规划
247247

248-
定义数组 $dp$,其中 $dp[i-1]$ 表示第 $i$ 个丑数,那么第 $n$ 个丑数就是 $dp[n - 1]$。最小的丑数是 $1$,所以 $dp[0]=1$。
248+
我们定义数组 $dp$,其中 $dp[i-1]$ 表示第 $i$ 个丑数,那么第 $n$ 个丑数就是 $dp[n - 1]$。最小的丑数是 $1$,所以 $dp[0]=1$。
249249

250250
定义 $3$ 个指针 $p_2$, $p_3$ 和 $p_5$,表示下一个丑数是当前指针指向的丑数乘以对应的质因数。初始时,三个指针的值都指向 $0$。
251251

lcof/面试题50. 第一个只出现一次的字符/README.md

+11-12
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9
4242

4343
### 方法一:数组或哈希表
4444

45-
我们可以使用哈希表或数组来统计每个字符出现的次数,然后再遍历一遍字符串,找到第一个出现次数为 $1$ 的字符。
45+
我们可以使用哈希表或数组 $cnt$ 来统计每个字符出现的次数,然后再遍历一遍字符串,找到第一个出现次数为 $1$ 的字符。
4646

4747
时间复杂度 $O(n)$,空间复杂度 $O(C)$。其中 $n$ 为字符串长度;而 $C$ 为字符集大小,本题中 $C=26$。
4848

@@ -121,12 +121,12 @@ func firstUniqChar(s string) byte {
121121

122122
```ts
123123
function firstUniqChar(s: string): string {
124-
const map = new Map();
124+
const cnt: number[] = Array(26).fill(0);
125125
for (const c of s) {
126-
map.set(c, !map.has(c));
126+
cnt[c.charCodeAt(0) - 97]++;
127127
}
128128
for (const c of s) {
129-
if (map.get(c)) {
129+
if (cnt[c.charCodeAt(0) - 97] === 1) {
130130
return c;
131131
}
132132
}
@@ -137,16 +137,15 @@ function firstUniqChar(s: string): string {
137137
#### Rust
138138

139139
```rust
140-
use std::collections::HashMap;
141140
impl Solution {
142141
pub fn first_uniq_char(s: String) -> char {
143-
let mut map = HashMap::new();
144-
for c in s.as_bytes() {
145-
map.insert(c, !map.contains_key(c));
142+
let mut cnt = [0; 26];
143+
for c in s.chars() {
144+
cnt[(c as usize) - ('a' as usize)] += 1;
146145
}
147-
for c in s.as_bytes() {
148-
if map[c] {
149-
return char::from(*c);
146+
for c in s.chars() {
147+
if cnt[(c as usize) - ('a' as usize)] == 1 {
148+
return c;
150149
}
151150
}
152151
' '
@@ -162,7 +161,7 @@ impl Solution {
162161
* @return {character}
163162
*/
164163
var firstUniqChar = function (s) {
165-
const cnt = new Array(26).fill(0);
164+
const cnt = Array(26).fill(0);
166165
for (const c of s) {
167166
cnt[c.charCodeAt(0) - 97]++;
168167
}

lcof/面试题50. 第一个只出现一次的字符/Solution.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @return {character}
44
*/
55
var firstUniqChar = function (s) {
6-
const cnt = new Array(26).fill(0);
6+
const cnt = Array(26).fill(0);
77
for (const c of s) {
88
cnt[c.charCodeAt(0) - 97]++;
99
}

lcof/面试题50. 第一个只出现一次的字符/Solution.rs

+6-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
use std::collections::HashMap;
21
impl Solution {
32
pub fn first_uniq_char(s: String) -> char {
4-
let mut map = HashMap::new();
5-
for c in s.as_bytes() {
6-
map.insert(c, !map.contains_key(c));
3+
let mut cnt = [0; 26];
4+
for c in s.chars() {
5+
cnt[(c as usize) - ('a' as usize)] += 1;
76
}
8-
for c in s.as_bytes() {
9-
if map[c] {
10-
return char::from(*c);
7+
for c in s.chars() {
8+
if cnt[(c as usize) - ('a' as usize)] == 1 {
9+
return c;
1110
}
1211
}
1312
' '

lcof/面试题50. 第一个只出现一次的字符/Solution.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
function firstUniqChar(s: string): string {
2-
const map = new Map();
2+
const cnt: number[] = Array(26).fill(0);
33
for (const c of s) {
4-
map.set(c, !map.has(c));
4+
cnt[c.charCodeAt(0) - 97]++;
55
}
66
for (const c of s) {
7-
if (map.get(c)) {
7+
if (cnt[c.charCodeAt(0) - 97] === 1) {
88
return c;
99
}
1010
}

lcof/面试题52. 两个链表的第一个公共节点/README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ edit_url: https://github.com/doocs/leetcode/edit/main/lcof/%E9%9D%A2%E8%AF%95%E9
7676

7777
我们可以用两个指针 $a$ 和 $b$ 分别指向两个链表的头节点,然后同时分别向后遍历,当 $a$ 到达链表 $A$ 的末尾时,令 $a$ 指向链表 $B$ 的头节点;当 $b$ 到达链表 $B$ 的末尾时,令 $b$ 指向链表 $A$ 的头节点。这样,当它们相遇时,所指向的节点就是第一个公共节点。
7878

79-
时间复杂度 $O(m + n)$,空间复杂度 $O(1)$。其中 $m$ 和 $n$ 分别为两个链表的长度。
79+
时间复杂度 $O(m + n)$,其中 $m$ 和 $n$ 分别为两个链表的长度。空间复杂度 $O(1)$
8080

8181
<!-- tabs:start -->
8282

solution/0400-0499/0400.Nth Digit/README_EN.md

+11-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,17 @@ tags:
4848

4949
<!-- solution:start -->
5050

51-
### Solution 1
51+
### Solution 1: Mathematics
52+
53+
The smallest and largest integers with $k$ digits are $10^{k-1}$ and $10^k-1$ respectively, so the total number of digits for $k$-digit numbers is $k \times 9 \times 10^{k-1}$.
54+
55+
We use $k$ to represent the number of digits of the current number, and $cnt$ to represent the total number of numbers with the current number of digits. Initially, $k=1$, $cnt=9$.
56+
57+
Each time we subtract $cnt \times k$ from $n$, when $n$ is less than or equal to $cnt \times k$, it means that the number corresponding to $n$ is within the range of numbers with the current number of digits. At this time, we can calculate the corresponding number.
58+
59+
The specific method is to first calculate which number of the current number of digits corresponds to $n$, and then calculate which digit of this number it is, so as to get the number on this digit.
60+
61+
The time complexity is $O(\log_{10} n)$.
5262

5363
<!-- tabs:start -->
5464

0 commit comments

Comments
 (0)