本题的关键是状态转移方程,定义 f ( i , j ) f(i,j) f(i,j)为坐标(0,0)到坐标(i,j)的不同路径数目,由于只能往下走或者往右走,往下走一步后剩余路径相当于坐标 ( 0 , 0 ) (0,0) (0,0)到坐标 ( i − 1 , j ) (i-1,j) (i−1,j),往右走一步后剩余路径相当于坐标 ( 0 , 0 ) (0,0) (0,0)到坐标 ( i , j − 1 ) (i,j-1) (i,j−1),再考虑上阻碍的问题,状态转移方程为:
f ( i , j ) = f ( i − 1 , j ) + f ( i , j − 1 ) , i f ( o b s t a c l e G r i d ( i , j ) ! = 0 ) f ( i , j ) = 0 , e l s e 初 始 条 件 f ( 0 , 0 ) = ( o b s t a c l e G r i d ( 0 , 0 ) = = 0 ) f ( 0 , i ) = ( o b s t a c l e G r i d ( 0 , 0 ) = = 0 ) & & ( o b s t a c l e G r i d ( 0 , 1 ) = = 0 ) & & . . . & & ( o b s t a c l e G r i d ( 0 , i − 1 ) = = 0 ) f(i,j)=f(i-1,j)+f(i,j-1),if(obstacleGrid(i,j)!=0)\\ f(i,j)=0,else\\ 初始条件\\ f(0,0)=(obstacleGrid(0,0)==0)\\ f(0,i)=(obstacleGrid(0,0)==0)\&\&(obstacleGrid(0,1)==0)\\\&\&...\&\&(obstacleGrid(0,i-1)==0)\\ f(i,j)=f(i−1,j)+f(i,j−1),if(obstacleGrid(i,j)!=0)f(i,j)=0,else初始条件f(0,0)=(obstacleGrid(0,0)==0)f(0,i)=(obstacleGrid(0,0)==0)&&(obstacleGrid(0,1)==0)&&...&&(obstacleGrid(0,i−1)==0)
观察到假如外层遍历i,内层遍历j时,求j的值只与上一轮i循环求得 f ( i − 1 , j ) f(i-1,j) f(i−1,j)的值和这一轮遍历j是上一次求得值 f ( i , j − 1 ) f(i,j-1) f(i,j−1)有关,所以可以直接用一个一维数组储存上一轮外层遍历计算的j的状态。
并且发现这个数组的元素个数等于内层循环遍历的次数,所以可以比较m和n的大小,如果m小就让m在内层遍历,如果n小就让n在内层遍历:
class Solution {
public:
int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid)
{
int m = obstacleGrid.size();
int n = obstacleGrid[0].size();
int ret;
if (n < m)
{
vector<int> dp(n);
dp[0] = (obstacleGrid[0][0] == 0);
for (int i = 0; i < m; ++i)
{
for (int j = 0; j < n; ++j)
{
if (obstacleGrid[i][j] == 1)
{
dp[j] = 0;
}
else
{
dp[j] = dp[j] + (j - 1 >= 0 ?
dp[j - 1] : 0);
}
}
}
ret = dp.back();
}
else
{
vector<int> dp(m);
dp[0] = (obstacleGrid[0][0] == 0);
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < m; ++j)
{
if (obstacleGrid[j][i] == 1)
{
dp[j] = 0;
}
else
{
dp[j] = dp[j] +
(j - 1 >= 0 ? dp[j - 1] : 0);
}
}
}
ret = dp.back();
}
return ret;
}
};
时间复杂度; O ( m ∗ n ) O(m*n) O(m∗n)
空间复杂度: O ( m i n ( m , n ) ) O(min(m,n)) O(min(m,n))