Skip to content

Commit 7063165

Browse files
authored
feat: add solutions to lc problem: No.63 (doocs#2749)
1 parent 13b21b8 commit 7063165

File tree

33 files changed

+631
-334
lines changed

33 files changed

+631
-334
lines changed

solution/0000-0099/0063.Unique Paths II/README.md

Lines changed: 193 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -49,16 +49,151 @@
4949

5050
## 解法
5151

52-
### 方法一:动态规划
52+
### 方法一:记忆化搜索
5353

54-
我们定义 $dp[i][j]$ 表示到达网格 $(i,j)$ 的路径数。
54+
我们设计一个函数 $dfs(i, j)$ 表示从网格 $(i, j)$ 到网格 $(m - 1, n - 1)$ 的路径数。其中 $m$ 和 $n$ 分别是网格的行数和列数
5555

56-
首先初始化 $dp$ 第一列和第一行的所有值,然后遍历其它行和列,有两种情况
56+
函数 $dfs(i, j)$ 的执行过程如下
5757

58-
- 若 $obstacleGrid[i][j] = 1$,说明路径数为 $0$,那么 $dp[i][j] = 0$;
59-
- 若 ¥ obstacleGrid[i][j] = 0$,则 $dp[i][j] = dp[i - 1][j] + dp[i][j - 1]$。
58+
- 如果 $i \ge m$ 或者 $j \ge n$,或者 $obstacleGrid[i][j] = 1$,则路径数为 $0$;
59+
- 如果 $i = m - 1$ 且 $j = n - 1$,则路径数为 $1$;
60+
- 否则,路径数为 $dfs(i + 1, j) + dfs(i, j + 1)$。
6061

61-
最后返回 $dp[m - 1][n - 1]$ 即可。
62+
为了避免重复计算,我们可以使用记忆化搜索的方法。
63+
64+
时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别是网格的行数和列数。
65+
66+
<!-- tabs:start -->
67+
68+
```python
69+
class Solution:
70+
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
71+
@cache
72+
def dfs(i: int, j: int) -> int:
73+
if i >= m or j >= n or obstacleGrid[i][j]:
74+
return 0
75+
if i == m - 1 and j == n - 1:
76+
return 1
77+
return dfs(i + 1, j) + dfs(i, j + 1)
78+
79+
m, n = len(obstacleGrid), len(obstacleGrid[0])
80+
return dfs(0, 0)
81+
```
82+
83+
```java
84+
class Solution {
85+
private Integer[][] f;
86+
private int[][] obstacleGrid;
87+
private int m;
88+
private int n;
89+
90+
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
91+
m = obstacleGrid.length;
92+
n = obstacleGrid[0].length;
93+
this.obstacleGrid = obstacleGrid;
94+
f = new Integer[m][n];
95+
return dfs(0, 0);
96+
}
97+
98+
private int dfs(int i, int j) {
99+
if (i >= m || j >= n || obstacleGrid[i][j] == 1) {
100+
return 0;
101+
}
102+
if (i == m - 1 && j == n - 1) {
103+
return 1;
104+
}
105+
if (f[i][j] == null) {
106+
f[i][j] = dfs(i + 1, j) + dfs(i, j + 1);
107+
}
108+
return f[i][j];
109+
}
110+
}
111+
```
112+
113+
```cpp
114+
class Solution {
115+
public:
116+
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
117+
int m = obstacleGrid.size(), n = obstacleGrid[0].size();
118+
int f[m][n];
119+
memset(f, -1, sizeof(f));
120+
function<int(int, int)> dfs = [&](int i, int j) {
121+
if (i >= m || j >= n || obstacleGrid[i][j]) {
122+
return 0;
123+
}
124+
if (i == m - 1 && j == n - 1) {
125+
return 1;
126+
}
127+
if (f[i][j] == -1) {
128+
f[i][j] = dfs(i + 1, j) + dfs(i, j + 1);
129+
}
130+
return f[i][j];
131+
};
132+
return dfs(0, 0);
133+
}
134+
};
135+
```
136+
137+
```go
138+
func uniquePathsWithObstacles(obstacleGrid [][]int) int {
139+
m, n := len(obstacleGrid), len(obstacleGrid[0])
140+
f := make([][]int, m)
141+
for i := range f {
142+
f[i] = make([]int, n)
143+
for j := range f[i] {
144+
f[i][j] = -1
145+
}
146+
}
147+
var dfs func(i, j int) int
148+
dfs = func(i, j int) int {
149+
if i >= m || j >= n || obstacleGrid[i][j] == 1 {
150+
return 0
151+
}
152+
if i == m-1 && j == n-1 {
153+
return 1
154+
}
155+
if f[i][j] == -1 {
156+
f[i][j] = dfs(i+1, j) + dfs(i, j+1)
157+
}
158+
return f[i][j]
159+
}
160+
return dfs(0, 0)
161+
}
162+
```
163+
164+
```ts
165+
function uniquePathsWithObstacles(obstacleGrid: number[][]): number {
166+
const m = obstacleGrid.length;
167+
const n = obstacleGrid[0].length;
168+
const f: number[][] = Array.from({ length: m }, () => Array(n).fill(-1));
169+
const dfs = (i: number, j: number): number => {
170+
if (i >= m || j >= n || obstacleGrid[i][j] === 1) {
171+
return 0;
172+
}
173+
if (i === m - 1 && j === n - 1) {
174+
return 1;
175+
}
176+
if (f[i][j] === -1) {
177+
f[i][j] = dfs(i + 1, j) + dfs(i, j + 1);
178+
}
179+
return f[i][j];
180+
};
181+
return dfs(0, 0);
182+
}
183+
```
184+
185+
<!-- tabs:end -->
186+
187+
### 方法二:动态规划
188+
189+
我们定义 $f[i][j]$ 表示到达网格 $(i,j)$ 的路径数。
190+
191+
首先初始化 $f$ 第一列和第一行的所有值,然后遍历其它行和列,有两种情况:
192+
193+
- 若 $obstacleGrid[i][j] = 1$,说明路径数为 $0$,那么 $f[i][j] = 0$;
194+
- 若 $obstacleGrid[i][j] = 0$,则 $f[i][j] = f[i - 1][j] + f[i][j - 1]$。
195+
196+
最后返回 $f[m - 1][n - 1]$ 即可。
62197

63198
时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别是网格的行数和列数。
64199

@@ -68,41 +203,41 @@
68203
class Solution:
69204
def uniquePathsWithObstacles(self, obstacleGrid: List[List[int]]) -> int:
70205
m, n = len(obstacleGrid), len(obstacleGrid[0])
71-
dp = [[0] * n for _ in range(m)]
206+
f = [[0] * n for _ in range(m)]
72207
for i in range(m):
73208
if obstacleGrid[i][0] == 1:
74209
break
75-
dp[i][0] = 1
210+
f[i][0] = 1
76211
for j in range(n):
77212
if obstacleGrid[0][j] == 1:
78213
break
79-
dp[0][j] = 1
214+
f[0][j] = 1
80215
for i in range(1, m):
81216
for j in range(1, n):
82217
if obstacleGrid[i][j] == 0:
83-
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
84-
return dp[-1][-1]
218+
f[i][j] = f[i - 1][j] + f[i][j - 1]
219+
return f[-1][-1]
85220
```
86221

87222
```java
88223
class Solution {
89224
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
90225
int m = obstacleGrid.length, n = obstacleGrid[0].length;
91-
int[][] dp = new int[m][n];
226+
int[][] f = new int[m][n];
92227
for (int i = 0; i < m && obstacleGrid[i][0] == 0; ++i) {
93-
dp[i][0] = 1;
228+
f[i][0] = 1;
94229
}
95230
for (int j = 0; j < n && obstacleGrid[0][j] == 0; ++j) {
96-
dp[0][j] = 1;
231+
f[0][j] = 1;
97232
}
98233
for (int i = 1; i < m; ++i) {
99234
for (int j = 1; j < n; ++j) {
100235
if (obstacleGrid[i][j] == 0) {
101-
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
236+
f[i][j] = f[i - 1][j] + f[i][j - 1];
102237
}
103238
}
104239
}
105-
return dp[m - 1][n - 1];
240+
return f[m - 1][n - 1];
106241
}
107242
}
108243
```
@@ -112,75 +247,96 @@ class Solution {
112247
public:
113248
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
114249
int m = obstacleGrid.size(), n = obstacleGrid[0].size();
115-
vector<vector<int>> dp(m, vector<int>(n));
250+
vector<vector<int>> f(m, vector<int>(n));
116251
for (int i = 0; i < m && obstacleGrid[i][0] == 0; ++i) {
117-
dp[i][0] = 1;
252+
f[i][0] = 1;
118253
}
119254
for (int j = 0; j < n && obstacleGrid[0][j] == 0; ++j) {
120-
dp[0][j] = 1;
255+
f[0][j] = 1;
121256
}
122257
for (int i = 1; i < m; ++i) {
123258
for (int j = 1; j < n; ++j) {
124259
if (obstacleGrid[i][j] == 0) {
125-
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
260+
f[i][j] = f[i - 1][j] + f[i][j - 1];
126261
}
127262
}
128263
}
129-
return dp[m - 1][n - 1];
264+
return f[m - 1][n - 1];
130265
}
131266
};
132267
```
133268
134269
```go
135270
func uniquePathsWithObstacles(obstacleGrid [][]int) int {
136271
m, n := len(obstacleGrid), len(obstacleGrid[0])
137-
dp := make([][]int, m)
272+
f := make([][]int, m)
138273
for i := 0; i < m; i++ {
139-
dp[i] = make([]int, n)
274+
f[i] = make([]int, n)
140275
}
141276
for i := 0; i < m && obstacleGrid[i][0] == 0; i++ {
142-
dp[i][0] = 1
277+
f[i][0] = 1
143278
}
144279
for j := 0; j < n && obstacleGrid[0][j] == 0; j++ {
145-
dp[0][j] = 1
280+
f[0][j] = 1
146281
}
147282
for i := 1; i < m; i++ {
148283
for j := 1; j < n; j++ {
149284
if obstacleGrid[i][j] == 0 {
150-
dp[i][j] = dp[i-1][j] + dp[i][j-1]
285+
f[i][j] = f[i-1][j] + f[i][j-1]
151286
}
152287
}
153288
}
154-
return dp[m-1][n-1]
289+
return f[m-1][n-1]
155290
}
156291
```
157292

158293
```ts
159294
function uniquePathsWithObstacles(obstacleGrid: number[][]): number {
160295
const m = obstacleGrid.length;
161296
const n = obstacleGrid[0].length;
162-
const dp = Array.from({ length: m }, () => new Array(n).fill(0));
297+
const f = Array.from({ length: m }, () => Array(n).fill(0));
163298
for (let i = 0; i < m; i++) {
164299
if (obstacleGrid[i][0] === 1) {
165300
break;
166301
}
167-
dp[i][0] = 1;
302+
f[i][0] = 1;
168303
}
169304
for (let i = 0; i < n; i++) {
170305
if (obstacleGrid[0][i] === 1) {
171306
break;
172307
}
173-
dp[0][i] = 1;
308+
f[0][i] = 1;
174309
}
175310
for (let i = 1; i < m; i++) {
176311
for (let j = 1; j < n; j++) {
177312
if (obstacleGrid[i][j] === 1) {
178313
continue;
179314
}
180-
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
315+
f[i][j] = f[i - 1][j] + f[i][j - 1];
181316
}
182317
}
183-
return dp[m - 1][n - 1];
318+
return f[m - 1][n - 1];
319+
}
320+
```
321+
322+
```ts
323+
function uniquePathsWithObstacles(obstacleGrid: number[][]): number {
324+
const m = obstacleGrid.length;
325+
const n = obstacleGrid[0].length;
326+
const f: number[][] = Array.from({ length: m }, () => Array(n).fill(-1));
327+
const dfs = (i: number, j: number): number => {
328+
if (i >= m || j >= n || obstacleGrid[i][j] === 1) {
329+
return 0;
330+
}
331+
if (i === m - 1 && j === n - 1) {
332+
return 1;
333+
}
334+
if (f[i][j] === -1) {
335+
f[i][j] = dfs(i + 1, j) + dfs(i, j + 1);
336+
}
337+
return f[i][j];
338+
};
339+
return dfs(0, 0);
184340
}
185341
```
186342

@@ -189,31 +345,28 @@ impl Solution {
189345
pub fn unique_paths_with_obstacles(obstacle_grid: Vec<Vec<i32>>) -> i32 {
190346
let m = obstacle_grid.len();
191347
let n = obstacle_grid[0].len();
192-
if obstacle_grid[0][0] == 1 || obstacle_grid[m - 1][n - 1] == 1 {
193-
return 0;
194-
}
195-
let mut dp = vec![vec![0; n]; m];
348+
let mut f = vec![vec![0; n]; m];
196349
for i in 0..n {
197350
if obstacle_grid[0][i] == 1 {
198351
break;
199352
}
200-
dp[0][i] = 1;
353+
f[0][i] = 1;
201354
}
202355
for i in 0..m {
203356
if obstacle_grid[i][0] == 1 {
204357
break;
205358
}
206-
dp[i][0] = 1;
359+
f[i][0] = 1;
207360
}
208361
for i in 1..m {
209362
for j in 1..n {
210363
if obstacle_grid[i][j] == 1 {
211364
continue;
212365
}
213-
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
366+
f[i][j] = f[i - 1][j] + f[i][j - 1];
214367
}
215368
}
216-
dp[m - 1][n - 1]
369+
f[m - 1][n - 1]
217370
}
218371
}
219372
```

0 commit comments

Comments
 (0)