





注意,纯递归是不行的,因为有大量的重复计算,需要加个缓存。
class Solution {
map<pair<int,int>, int> map;//用来保存计算结果
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid)
{
if (obstacleGrid[0][0] == 1)//起点有障碍物,那么直接返回0
return 0;
if (obstacleGrid[obstacleGrid.size() - 1][obstacleGrid[0].size() - 1] == 1)//终点存在障碍物
return 0;
return dfs(obstacleGrid, 0, 0);
}
int dfs(vector<vector<int>>& obstacleGrid, int i, int j)
{
//如果到达当前点的走法总数已经算出,那么直接返回
if (map.find({ i,j }) != map.end())
return map[{i, j}];
//越界检查和障碍物检查
if (i >= obstacleGrid.size() || j >= obstacleGrid[0].size() || obstacleGrid[i][j] == 1)
return 0;
//到达左下角,返回1
if (i == obstacleGrid.size() - 1 && j == obstacleGrid[0].size() - 1)
return 1;
//到达当前点的走法
map[{i, j}] =dfs(obstacleGrid, i+1, j) + dfs(obstacleGrid, i, j+1);
return map[{i, j}];
}
};

if 当前点不是障碍物:
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
else:
dp[i][j] = 0
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid)
{
if (obstacleGrid[0][0] == 1) return 0;
int r = obstacleGrid.size();
int c = obstacleGrid[0].size();
if (obstacleGrid[r - 1][c - 1] == 1) return 0;
vector<vector<int>> dp(r, vector<int>(c));
dp[0][0] = 1;
//处理第一列
for (int i = 1; i < r; ++i)
{
//当前格子有障碍或者当前格子所处列有障碍物
if (obstacleGrid[i][0] == 1 || dp[i - 1][0] == 0)
{
dp[i][0] = 0;
}
else
{
dp[i][0] = 1;
}
}
//处理第一行
for (int j = 1; j < c; j++)
{
if (obstacleGrid[0][j] == 1 || dp[0][j - 1] == 0)
{
dp[0][j] = 0;
}
else
{
dp[0][j] = 1;
}
}
for (int i = 1; i < r; i++)
{
for (int j = 1; j < c; j++)
{
//当前格子存在障碍物
if (obstacleGrid[i][j] == 1)
dp[i][j] = 0;
else//路径总数来自于上方(dp[i-1][j])和左方(dp[i][j-1])
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[r - 1][c - 1];
}
};

同样,反着推的时候也需要处理下边界问题,也就是最后一行,最后一列需要单独处理一下。这里的思路跟前一种解法是一样的,只是倒退来的。

时间复杂度:O(M * N) 空间复杂度:O(M * N)
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid)
{
if (obstacleGrid[0][0] == 1) return 0;
int r = obstacleGrid.size();
int c = obstacleGrid[0].size();
if (obstacleGrid[r - 1][c - 1] == 1) return 0;
vector<vector<long>> dp(r, vector<long>(c));
//最小子结果
dp[r - 1][c - 1] = 1;
//处理第一列
for (int i = r - 2; i >= 0; --i)
{
//当前格子有障碍或者当前格子所处列有障碍物
if (obstacleGrid[i][c - 1] == 1 || dp[i+1][c - 1] == 0)
{
dp[i][c - 1] = 0;
}
else
{
dp[i][c - 1] = 1;
}
}
//处理第一行
for (int j = c - 2; j >= 0; --j)
{
if (obstacleGrid[r - 1][j] == 1 || dp[r - 1][j+1] == 0)
{
dp[r - 1][j] = 0;
}
else
{
dp[r - 1][j] = 1;
}
}
for (int i = r - 2; i >= 0; i--)
{
for (int j = c - 2; j >= 0; j--)
{
//当前格子存在障碍物
if (obstacleGrid[i][j] == 1)
dp[i][j] = 0;
else//路径总数来自于上方(dp[i-1][j])和左方(dp[i][j-1])
dp[i][j] = dp[i + 1][j] + dp[i][j + 1];
}
}
return dp[0][0];
}
};
dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
计算当前值 = 以求出的左边值 + 上一次迭代同位置的值
dp[j] = dp[j - 1] + dp[j]时间复杂度:O(M * N) 空间复杂度:O(M)
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid)
{
if (obstacleGrid[0][0] == 1) return 0;
int r = obstacleGrid.size();
int c = obstacleGrid[0].size();
if (obstacleGrid[r - 1][c - 1] == 1) return 0;
vector<int> dp(c);
//这里滚动数组的第一个元素,即每一行的第一个元素,只要当前格子没有障碍物,就都是1
dp[0] = 1;
for (int i = 0; i<r; i++)
{
for (int j = 0; j <c; j++)
{
//有障碍物的格子直接赋0
if (obstacleGrid[i][j] == 1)
dp[j] = 0;
//否则dp[j]的值由左方和上一次迭代的dp[j]累加而来
else if (obstacleGrid[i][j] == 0 && j - 1 >=0)
dp[j] = dp[j] + dp[j - 1];
}
}
return dp[c-1];
}
};