方法:dp
class Solution {
#define maxn 110
int dp[maxn][maxn];
public:
int uniquePaths(int m, int n) {
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (i == 1 || j == 1) dp[i][j] = 1;
else {
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
}
}
return dp[m][n];
}
};
$时间复杂度O(n*m),空间复杂度O(n*m);
优化:
class Solution {
#define maxn 110
int dp[maxn];
public:
int uniquePaths(int m, int n) {
for (int i = 1; i <= n; ++i) dp[i] = 1;
for (int j = 2; j <= m; ++j)
for (int i = 2; i <= n; ++i) {
dp[i] += dp[i-1];
}
return dp[n];
}
};
$时间复杂度O(n*m),空间复杂度O(n);
方法:数论
由于无论怎么走,走到终点一共要走m+n-2步。其中向下的步数为m-1步,所以就转化为组合数的问题,在m+n-2步数中选出m-1步数 a代表m+n-2,b代表m-1
由于分子的数据范围可能溢出,所以需要在计算分子的时候不断除以分母;
class Solution {
typedef long long ll;
public:
int uniquePaths(int m, int n) {
ll num = 1;
int den = m - 1, cnt = m - 1, t = m + n - 2;
while (cnt--) {
num *= (t--);
while (den != 0 && num % den == 0) {
num /= den;
den--;
}
}
return num;
}
};
$时间复杂度O(m),空间复杂度O(1);
方法:dp
class Solution {
#define maxn 110
int dp[maxn][maxn];
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int n = obstacleGrid.size(), m = obstacleGrid[0].size();
if (obstacleGrid[n - 1][m - 1] == 1 || obstacleGrid[0][0] == 1) return 0;
for (int i = 0; i < n && obstacleGrid[i][0] == 0; ++i) dp[i][0] = 1;
for (int j = 0; j < m && obstacleGrid[0][j] == 0; j++) dp[0][j] = 1;
for (int i = 1; i < n; ++i)
for (int j = 1; j < m; ++j) {
if (obstacleGrid[i][j] == 1) continue;
dp[i][j] = dp[i-1][j] + dp[i][j-1];
}
return dp[n-1][m-1];
}
};
$时间复杂度O(n*m),空间复杂度O(n*m);
空间优化
class Solution {
#define maxn 110
int dp[maxn];
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) {
int n = obstacleGrid.size(), m = obstacleGrid[0].size();
for (int j = 0; j < m; ++j) {
if (obstacleGrid[0][j] == 1) dp[j] = 0;
else if (j == 0) dp[j] = 1;
else dp[j] = dp[j-1];
}
for (int i = 1; i < n; ++i) {
for (int j = 0; j < m; ++j) {
if (obstacleGrid[i][j] == 1) dp[j] = 0;
else if (j != 0) {
dp[j] += dp[j-1];
}
}
}
return dp[m-1];
}
};
$时间复杂度O(n*m),空间复杂度O(m);