Unique Paths
描述
A robot is located at the top-left corner of a m × 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?
Note: m
and n
will be at most 100.
深搜
- Python
- Java
- C++
// Unique Paths
// 深搜,小集合可以过,大集合会超时
// 时间复杂度O(n^4),空间复杂度O(n)
public class Solution {
public int uniquePaths(int m, int n) {
if (m < 1 || n < 1) return 0; // 终止条件
if (m == 1 && n == 1) return 1; // 收敛条件
return uniquePaths(m - 1, n) + uniquePaths(m, n - 1);
}
}
// Unique Paths
// 深搜,小集合可以过,大集合会超时
// 时间复杂度O(n^4),空间复杂度O(n)
class Solution {
public:
int uniquePaths(int m, int n) {
if (m < 1 || n < 1) return 0; // 终止条件
if (m == 1 && n == 1) return 1; // 收敛条件
return uniquePaths(m - 1, n) + uniquePaths(m, n - 1);
}
};
# Unique Paths
# 深搜,小集合可以过,大集合会超时
# 时间复杂度O(n^4),空间复杂度O(n)
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
if m < 1 or n < 1: return 0 # 终止条件
if m == 1 and n == 1: return 1 # 收敛条件
return self.uniquePaths(m - 1, n) + self.uniquePaths(m, n - 1)
备忘录法
给前面的深搜,加个缓存,就可以过大集合了。即备忘录法。
- Java
- C++
// Unique Paths
// 深搜 + 缓存,即备忘录法
// 时间复杂度O(n^2),空间复杂度O(n^2)
public class Solution {
public int uniquePaths(int m, int n) {
// f[x][y] 表示 从(0,0)到(x,y)的路径条数
f = new int[m][n];
f[0][0] = 1;
return dfs(m - 1, n - 1);
}
int dfs(int x, int y) {
if (x < 0 || y < 0) return 0; // 数据非法,终止条件
if (x == 0 && y == 0) return f[0][0]; // 回到起点,收敛条件
if (f[x][y] > 0) {
return f[x][y];
} else {
return f[x][y] = dfs(x - 1, y) + dfs(x, y - 1);
}
}
private int[][] f; // 缓存
}
// Unique Paths
// 深搜 + 缓存,即备忘录法
// 时间复杂度O(n^2),空间复杂度O(n^2)
class Solution {
public:
int uniquePaths(int m, int n) {
// f[x][y] 表示 从(0,0)到(x,y)的路径条数
f = vector<vector<int> >(m, vector<int>(n, 0));
f[0][0] = 1;
return dfs(m - 1, n - 1);
}
private:
vector<vector<int> > f; // 缓存
int dfs(int x, int y) {
if (x < 0 || y < 0) return 0; // 数据非法,终止条件
if (x == 0 && y == 0) return f[0][0]; // 回到起点,收敛条件
if (f[x][y] > 0) {
return f[x][y];
} else {
return f[x][y] = dfs(x - 1, y) + dfs(x, y - 1);
}
}
};
# Unique Paths
# 深搜 + 缓存,即备忘录法
# 时间复杂度O(n^2),空间复杂度O(n^2)
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
# f[x][y] 表示 从(0,0)到(x,y)的路径条数
self.f = [[0] * n for _ in range(m)]
self.f[0][0] = 1
return self.dfs(m - 1, n - 1)
def dfs(self, x: int, y: int) -> int:
if x < 0 or y < 0: return 0 # 数据非法,终止条件
if x == 0 and y == 0: return self.f[0][0] # 回到起点,收敛条件
if self.f[x][y] > 0:
return self.f[x][y]
else:
self.f[x][y] = self.dfs(x - 1, y) + self.dfs(x, y - 1)
return self.f[x][y]
动规
既然可以用备忘录法自顶向下解决,也一定可以用动规自底向上解决。
设状态为f[i][j]
,表示从起点(1,1)
到达(i,j)
的路线条数,则状态转移方程为:
f[i][j]=f[i-1][j]+f[i][j-1]
- Java
- C++
// 动规,滚动数组
// 时间复杂度O(n^2),空间复杂度O(n)
public class Solution {
public int uniquePaths(int m, int n) {
int[] f = new int[n];
f[0] = 1;
for (int i = 0; i < m; i++) {
for (int j = 1; j < n; j++) {
// 左边的f[j],表示更新后的f[j],与公式中的f[i][j]对应
// 右边的f[j],表示老的f[j],与公式中的f[i-1][j]对应
f[j] = f[j] + f[j - 1];
}
}
return f[n - 1];
}
}
// Unique Paths
// 动规,滚动数组
// 时间复杂度O(n^2),空间复杂度O(n)
class Solution {
public:
int uniquePaths(int m, int n) {
vector<int> f(n, 0);
f[0] = 1;
for (int i = 0; i < m; i++) {
for (int j = 1; j < n; j++) {
// 左边的f[j],表示更新后的f[j],与公式中的f[i][j]对应
// 右边的f[j],表示老的f[j],与公式中的f[i-1][j]对应
f[j] = f[j] + f[j - 1];
}
}
return f[n - 1];
}
};
# 动规,滚动数组
# 时间复杂度O(n^2),空间复杂度O(n)
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
f = [0] * n
f[0] = 1
for i in range(m):
for j in range(1, n):
# 左边的f[j],表示更新后的f[j],与公式中的f[i][j]对应
# 右边的f[j],表示老的f[j],与公式中的f[i-1][j]对应
f[j] = f[j] + f[j - 1]
return f[n - 1]