Skip to content

Commit 4b2ed19

Browse files
authored
feat: add solutions to lcci problems: No.08.10~08.12 (#2691)
1 parent a043ada commit 4b2ed19

27 files changed

+714
-555
lines changed

lcci/08.10.Color Fill/README.md

+56-5
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,9 @@ sr = 1, sc = 1, newColor = 2
3131

3232
## 解法
3333

34-
### 方法一:Flood fill 算法
34+
### 方法一:DFS
3535

36-
Flood fill 算法是从一个区域中提取若干个连通的点与其他相邻区域区分开(或分别染成不同颜色)的经典算法。因为其思路类似洪水从一个区域扩散到所有能到达的区域而得名。
37-
38-
最简单的实现方法是采用 DFS 的递归方法,也可以采用 BFS 的迭代来实现。
36+
我们设计一个函数 $dfs(i, j)$,表示从 $(i, j)$ 开始填充颜色。如果 $(i, j)$ 不在图像范围内,或者 $(i, j)$ 的颜色不是原来的颜色,或者 $(i, j)$ 的颜色已经被填充成新的颜色,就返回。否则,将 $(i, j)$ 的颜色填充成新的颜色,然后递归搜索 $(i, j)$ 的上下左右四个方向。
3937

4038
时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为图像的行数和列数。
4139

@@ -135,6 +133,32 @@ func floodFill(image [][]int, sr int, sc int, newColor int) [][]int {
135133
}
136134
```
137135

136+
```ts
137+
function floodFill(image: number[][], sr: number, sc: number, newColor: number): number[][] {
138+
const dfs = (i: number, j: number): void => {
139+
if (i < 0 || i >= m) {
140+
return;
141+
}
142+
if (j < 0 || j >= n) {
143+
return;
144+
}
145+
if (image[i][j] !== oc || image[i][j] === nc) {
146+
return;
147+
}
148+
image[i][j] = nc;
149+
for (let k = 0; k < 4; ++k) {
150+
dfs(i + dirs[k], j + dirs[k + 1]);
151+
}
152+
};
153+
const dirs: number[] = [-1, 0, 1, 0, -1];
154+
const [m, n] = [image.length, image[0].length];
155+
const oc = image[sr][sc];
156+
const nc = newColor;
157+
dfs(sr, sc);
158+
return image;
159+
}
160+
```
161+
138162
```rust
139163
impl Solution {
140164
fn dfs(i: usize, j: usize, target: i32, new_color: i32, image: &mut Vec<Vec<i32>>) {
@@ -170,7 +194,11 @@ impl Solution {
170194

171195
<!-- tabs:end -->
172196

173-
### 方法二
197+
### 方法二:BFS
198+
199+
我们可以使用广度优先搜索的方法,从起始点开始,将起始点的颜色填充成新的颜色,然后将起始点加入队列。每次从队列中取出一个点,然后将其上下左右四个方向的点加入队列,直到队列为空。
200+
201+
时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为图像的行数和列数。
174202

175203
<!-- tabs:start -->
176204

@@ -274,6 +302,29 @@ func floodFill(image [][]int, sr int, sc int, newColor int) [][]int {
274302
}
275303
```
276304

305+
```ts
306+
function floodFill(image: number[][], sr: number, sc: number, newColor: number): number[][] {
307+
if (image[sr][sc] === newColor) {
308+
return image;
309+
}
310+
const q: number[][] = [[sr, sc]];
311+
const oc = image[sr][sc];
312+
image[sr][sc] = newColor;
313+
const dirs: number[] = [-1, 0, 1, 0, -1];
314+
while (q.length) {
315+
const [i, j] = q.pop()!;
316+
for (let k = 0; k < 4; ++k) {
317+
const [x, y] = [i + dirs[k], j + dirs[k + 1]];
318+
if (x >= 0 && x < image.length && y >= 0 && y < image[0].length && image[x][y] === oc) {
319+
q.push([x, y]);
320+
image[x][y] = newColor;
321+
}
322+
}
323+
}
324+
return image;
325+
}
326+
```
327+
277328
<!-- tabs:end -->
278329

279330
<!-- end -->

lcci/08.10.Color Fill/README_EN.md

+57-6
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,11 @@ to the starting pixel.</pre>
3838

3939
## Solutions
4040

41-
### Solution 1: Flood Fill Algorithm
41+
### Solution 1: DFS
4242

43-
The Flood Fill algorithm is a classic algorithm used to extract several connected points from a region and distinguish them from other adjacent regions (or color them differently). It is named for its strategy, which is similar to a flood spreading from one area to all reachable areas.
43+
We design a function $dfs(i, j)$ to start filling color from $(i, j)$. If $(i, j)$ is not within the image range, or the color of $(i, j)$ is not the original color, or the color of $(i, j)$ has been filled with the new color, then return. Otherwise, fill the color of $(i, j)$ with the new color, and then recursively search the four directions: up, down, left, and right of $(i, j)$.
4444

45-
The simplest implementation method is to use the recursive method of DFS, or it can be implemented iteratively using BFS.
46-
47-
The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Here, $m$ and $n$ are the number of rows and columns of the image, respectively.
45+
The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Where $m$ and $n$ are the number of rows and columns in the image, respectively.
4846

4947
<!-- tabs:start -->
5048

@@ -142,6 +140,32 @@ func floodFill(image [][]int, sr int, sc int, newColor int) [][]int {
142140
}
143141
```
144142

143+
```ts
144+
function floodFill(image: number[][], sr: number, sc: number, newColor: number): number[][] {
145+
const dfs = (i: number, j: number): void => {
146+
if (i < 0 || i >= m) {
147+
return;
148+
}
149+
if (j < 0 || j >= n) {
150+
return;
151+
}
152+
if (image[i][j] !== oc || image[i][j] === nc) {
153+
return;
154+
}
155+
image[i][j] = nc;
156+
for (let k = 0; k < 4; ++k) {
157+
dfs(i + dirs[k], j + dirs[k + 1]);
158+
}
159+
};
160+
const dirs: number[] = [-1, 0, 1, 0, -1];
161+
const [m, n] = [image.length, image[0].length];
162+
const oc = image[sr][sc];
163+
const nc = newColor;
164+
dfs(sr, sc);
165+
return image;
166+
}
167+
```
168+
145169
```rust
146170
impl Solution {
147171
fn dfs(i: usize, j: usize, target: i32, new_color: i32, image: &mut Vec<Vec<i32>>) {
@@ -177,7 +201,11 @@ impl Solution {
177201

178202
<!-- tabs:end -->
179203

180-
### Solution 2
204+
### Solution 2: BFS
205+
206+
We can use the method of breadth-first search. Starting from the initial point, fill the color of the initial point with the new color, and then add the initial point to the queue. Each time a point is taken from the queue, the points in the four directions: up, down, left, and right are added to the queue, until the queue is empty.
207+
208+
The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Where $m$ and $n$ are the number of rows and columns in the image, respectively.
181209

182210
<!-- tabs:start -->
183211

@@ -281,6 +309,29 @@ func floodFill(image [][]int, sr int, sc int, newColor int) [][]int {
281309
}
282310
```
283311

312+
```ts
313+
function floodFill(image: number[][], sr: number, sc: number, newColor: number): number[][] {
314+
if (image[sr][sc] === newColor) {
315+
return image;
316+
}
317+
const q: number[][] = [[sr, sc]];
318+
const oc = image[sr][sc];
319+
image[sr][sc] = newColor;
320+
const dirs: number[] = [-1, 0, 1, 0, -1];
321+
while (q.length) {
322+
const [i, j] = q.pop()!;
323+
for (let k = 0; k < 4; ++k) {
324+
const [x, y] = [i + dirs[k], j + dirs[k + 1]];
325+
if (x >= 0 && x < image.length && y >= 0 && y < image[0].length && image[x][y] === oc) {
326+
q.push([x, y]);
327+
image[x][y] = newColor;
328+
}
329+
}
330+
}
331+
return image;
332+
}
333+
```
334+
284335
<!-- tabs:end -->
285336

286337
<!-- end -->

lcci/08.10.Color Fill/Solution.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
function floodFill(image: number[][], sr: number, sc: number, newColor: number): number[][] {
2+
const dfs = (i: number, j: number): void => {
3+
if (i < 0 || i >= m) {
4+
return;
5+
}
6+
if (j < 0 || j >= n) {
7+
return;
8+
}
9+
if (image[i][j] !== oc || image[i][j] === nc) {
10+
return;
11+
}
12+
image[i][j] = nc;
13+
for (let k = 0; k < 4; ++k) {
14+
dfs(i + dirs[k], j + dirs[k + 1]);
15+
}
16+
};
17+
const dirs: number[] = [-1, 0, 1, 0, -1];
18+
const [m, n] = [image.length, image[0].length];
19+
const oc = image[sr][sc];
20+
const nc = newColor;
21+
dfs(sr, sc);
22+
return image;
23+
}

lcci/08.10.Color Fill/Solution2.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
function floodFill(image: number[][], sr: number, sc: number, newColor: number): number[][] {
2+
if (image[sr][sc] === newColor) {
3+
return image;
4+
}
5+
const q: number[][] = [[sr, sc]];
6+
const oc = image[sr][sc];
7+
image[sr][sc] = newColor;
8+
const dirs: number[] = [-1, 0, 1, 0, -1];
9+
while (q.length) {
10+
const [i, j] = q.pop()!;
11+
for (let k = 0; k < 4; ++k) {
12+
const [x, y] = [i + dirs[k], j + dirs[k + 1]];
13+
if (x >= 0 && x < image.length && y >= 0 && y < image[0].length && image[x][y] === oc) {
14+
q.push([x, y]);
15+
image[x][y] = newColor;
16+
}
17+
}
18+
}
19+
return image;
20+
}

lcci/08.11.Coin/README.md

+4-6
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ $$
6363

6464
时间复杂度 $O(C \times n)$,空间复杂度 $O(C \times n)$,其中 $C$ 为硬币的种类数。
6565

66-
我们注意到,$f[i][j]$ 的计算只与 $f[i−1][..]$ 有关,因此我们可以去掉第一维,将空间复杂度优化到 $O(n)$。
67-
6866
<!-- tabs:start -->
6967

7068
```python
@@ -149,9 +147,7 @@ func waysToChange(n int) int {
149147
function waysToChange(n: number): number {
150148
const mod = 10 ** 9 + 7;
151149
const coins: number[] = [25, 10, 5, 1];
152-
const f: number[][] = Array(5)
153-
.fill(0)
154-
.map(() => Array(n + 1).fill(0));
150+
const f: number[][] = Array.from({ length: 5 }, () => Array(n + 1).fill(0));
155151
f[0][0] = 1;
156152
for (let i = 1; i <= 4; ++i) {
157153
for (let j = 0; j <= n; ++j) {
@@ -167,7 +163,9 @@ function waysToChange(n: number): number {
167163

168164
<!-- tabs:end -->
169165

170-
### 方法二
166+
### 方法二:动态规划(空间优化)
167+
168+
我们注意到,$f[i][j]$ 的计算只与 $f[i−1][..]$ 有关,因此我们可以去掉第一维,将空间复杂度优化到 $O(n)$。
171169

172170
<!-- tabs:start -->
173171

lcci/08.11.Coin/README_EN.md

+4-6
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,6 @@ The final answer is $f[4][n]$.
7575

7676
The time complexity is $O(C \times n)$, and the space complexity is $O(C \times n)$, where $C$ is the number of types of coins.
7777

78-
We notice that the calculation of $f[i][j]$ is only related to $f[i−1][..]$, so we can remove the first dimension and optimize the space complexity to $O(n)$.
79-
8078
<!-- tabs:start -->
8179

8280
```python
@@ -161,9 +159,7 @@ func waysToChange(n int) int {
161159
function waysToChange(n: number): number {
162160
const mod = 10 ** 9 + 7;
163161
const coins: number[] = [25, 10, 5, 1];
164-
const f: number[][] = Array(5)
165-
.fill(0)
166-
.map(() => Array(n + 1).fill(0));
162+
const f: number[][] = Array.from({ length: 5 }, () => Array(n + 1).fill(0));
167163
f[0][0] = 1;
168164
for (let i = 1; i <= 4; ++i) {
169165
for (let j = 0; j <= n; ++j) {
@@ -179,7 +175,9 @@ function waysToChange(n: number): number {
179175

180176
<!-- tabs:end -->
181177

182-
### Solution 2
178+
### Solution 2: Dynamic Programming (Space Optimization)
179+
180+
We notice that the calculation of $f[i][j]$ is only related to $f[i−1][..]$. Therefore, we can remove the first dimension and optimize the space complexity to $O(n)$.
183181

184182
<!-- tabs:start -->
185183

lcci/08.11.Coin/Solution.ts

+1-3
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
function waysToChange(n: number): number {
22
const mod = 10 ** 9 + 7;
33
const coins: number[] = [25, 10, 5, 1];
4-
const f: number[][] = Array(5)
5-
.fill(0)
6-
.map(() => Array(n + 1).fill(0));
4+
const f: number[][] = Array.from({ length: 5 }, () => Array(n + 1).fill(0));
75
f[0][0] = 1;
86
for (let i = 1; i <= 4; ++i) {
97
for (let j = 0; j <= n; ++j) {

0 commit comments

Comments
 (0)