172 lines
4.0 KiB
Markdown
172 lines
4.0 KiB
Markdown
|
||
## 题目地址
|
||
https://leetcode.com/problems/unique-paths/description/
|
||
|
||
## 题目描述
|
||
```
|
||
|
||
A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).
|
||
|
||
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
|
||
|
||
How many possible unique paths are there?
|
||
```
|
||
![](https://tva1.sinaimg.cn/large/0082zybply1gca6k99jmoj30b4053mxa.jpg)
|
||
|
||
```
|
||
Above is a 7 x 3 grid. How many possible unique paths are there?
|
||
|
||
Note: m and n will be at most 100.
|
||
|
||
Example 1:
|
||
|
||
Input: m = 3, n = 2
|
||
Output: 3
|
||
Explanation:
|
||
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
|
||
1. Right -> Right -> Down
|
||
2. Right -> Down -> Right
|
||
3. Down -> Right -> Right
|
||
Example 2:
|
||
|
||
Input: m = 7, n = 3
|
||
Output: 28
|
||
```
|
||
|
||
## 思路
|
||
|
||
这是一道典型的适合使用动态规划解决的题目,它和爬楼梯等都属于动态规划中最简单的题目,因此也经常会被用于面试之中。
|
||
|
||
读完题目你就能想到动态规划的话,建立模型并解决恐怕不是难事。其实我们很容易看出,由于机器人只能右移动和下移动,
|
||
因此第[i, j]个格子的总数应该等于[i - 1, j] + [i, j -1], 因为第[i,j]个格子一定是从左边或者上面移动过来的。
|
||
|
||
![](https://tva1.sinaimg.cn/large/0082zybply1gca6kj31o4j304z07gt8u.jpg)
|
||
|
||
代码大概是:
|
||
|
||
JS Code:
|
||
|
||
```js
|
||
const dp = [];
|
||
for (let i = 0; i < m + 1; i++) {
|
||
dp[i] = [];
|
||
dp[i][0] = 0;
|
||
}
|
||
for (let i = 0; i < n + 1; i++) {
|
||
dp[0][i] = 0;
|
||
}
|
||
for (let i = 1; i < m + 1; i++) {
|
||
for(let j = 1; j < n + 1; j++) {
|
||
dp[i][j] = j === 1 ? 1 : dp[i - 1][j] + dp[i][j - 1]; // 转移方程
|
||
}
|
||
}
|
||
|
||
return dp[m][n];
|
||
|
||
```
|
||
|
||
Python Code:
|
||
|
||
```python
|
||
class Solution:
|
||
def uniquePaths(self, m: int, n: int) -> int:
|
||
d = [[1] * n for _ in range(m)]
|
||
|
||
for col in range(1, m):
|
||
for row in range(1, n):
|
||
d[col][row] = d[col - 1][row] + d[col][row - 1]
|
||
|
||
return d[m - 1][n - 1]
|
||
```
|
||
|
||
**复杂度分析**
|
||
|
||
- 时间复杂度:$O(M * N)$
|
||
- 空间复杂度:$O(M * N)$
|
||
|
||
由于dp[i][j] 只依赖于左边的元素和上面的元素,因此空间复杂度可以进一步优化, 优化到O(n).
|
||
|
||
![](https://tva1.sinaimg.cn/large/0082zybply1gca6l63ax7j30gr09w3zp.jpg)
|
||
|
||
具体代码请查看代码区。
|
||
|
||
|
||
当然你也可以使用记忆化递归的方式来进行,由于递归深度的原因,性能比上面的方法差不少:
|
||
|
||
> 直接暴力递归的话会超时。
|
||
|
||
Python3 Code:
|
||
```python
|
||
class Solution:
|
||
visited = dict()
|
||
|
||
def uniquePaths(self, m: int, n: int) -> int:
|
||
if (m, n) in self.visited:
|
||
return self.visited[(m, n)]
|
||
if m == 1 or n == 1:
|
||
return 1
|
||
cnt = self.uniquePaths(m - 1, n) + self.uniquePaths(m, n - 1)
|
||
self.visited[(m, n)] = cnt
|
||
return cnt
|
||
```
|
||
|
||
## 关键点
|
||
|
||
- 记忆化递归
|
||
- 基本动态规划问题
|
||
- 空间复杂度可以进一步优化到O(n), 这会是一个考点
|
||
## 代码
|
||
|
||
代码支持JavaScript,Python3
|
||
|
||
JavaScript Code:
|
||
|
||
```js
|
||
/*
|
||
* @lc app=leetcode id=62 lang=javascript
|
||
*
|
||
* [62] Unique Paths
|
||
*
|
||
* https://leetcode.com/problems/unique-paths/description/
|
||
*/
|
||
/**
|
||
* @param {number} m
|
||
* @param {number} n
|
||
* @return {number}
|
||
*/
|
||
var uniquePaths = function(m, n) {
|
||
const dp = Array(n).fill(1);
|
||
|
||
for(let i = 1; i < m; i++) {
|
||
for(let j = 1; j < n; j++) {
|
||
dp[j] = dp[j] + dp[j - 1];
|
||
}
|
||
}
|
||
|
||
return dp[n - 1];
|
||
};
|
||
```
|
||
|
||
Python3 Code:
|
||
|
||
```python
|
||
class Solution:
|
||
|
||
def uniquePaths(self, m: int, n: int) -> int:
|
||
dp = [1] * n
|
||
for _ in range(1, m):
|
||
for j in range(1, n):
|
||
dp[j] += dp[j - 1]
|
||
return dp[n - 1]
|
||
```
|
||
|
||
**复杂度分析**
|
||
|
||
- 时间复杂度:$O(M * N)$
|
||
- 空间复杂度:$O(N)$
|
||
|
||
## 扩展
|
||
|
||
你可以做到比$O(M * N)$更快,比$O(N)$更省内存的算法么?这里有一份[资料](https://leetcode.com/articles/unique-paths/)可供参考。
|
||
> 提示: 考虑数学
|