leecode/problems/62.unique-paths.md
2020-05-22 18:17:19 +08:00

172 lines
4.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

## 题目地址
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), 这会是一个考点
## 代码
代码支持JavaScriptPython3
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/)可供参考。
> 提示: 考虑数学