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?
Above is a 3 x 7 grid. How many possible unique paths are there? Note: m and n will be at most 100.
解题分析:
一个m行,n列的矩阵,机器人从左上走到右下总共需要的步数是m+n-2,其中向下走的步数是m-1,
因此问题变成了在m+n-2个操作中,选择m–1个时间点向下走,选择方式有多少种,即组合数 C(m+n-2, m-1)
class Solution { public: int uniquePaths(int m, int n) { return combination(m+n-2, n-1); } int combination(int m, int n) { assert(m >= 0 && n >= 0 && m >= n); int tmp[m-n+1][n+1]; for (int i = 0; i < m - n + 1; ++i) { for (int j = 0; j < n + 1; ++j) { if (i == 0 || j == 0) { tmp[i][j] = 1; } else { tmp[i][j] = tmp[i-1][j] + tmp[i][j-1]; } } } return tmp[m-n][n]; } };
如何计算组合数:
设状态为f[i][j],表示从起点(1;1)到达(i; j)的路线条数,则状态转移方程为:
f[i][j]=f[i-1][j]+f[i][j-1]
这个类似于跳台阶,我们要达到f[i][j], 只能从 f[i-1][j] 和 f[i][j-1] 这两个点出发,因为只能在相邻的横向或纵向之间行进
注意边界情况
方法二:
深度优先搜索,并且在搜索过程中利用二维数组做缓存
class Solution { public: int uniquePaths(int m, int n) { // 行列数都从1开始,0行0列未用 this->f = vector<vector<int>>(m + 1, vector<int>(n + 1, 0)); return dfs(m, n); } private: vector<vector<int>> f; // 缓存 int dfs(int x, int y) { if (x < 1 || y < 1) return 0; // 收据非法,终止条件 if (x == 1 && y == 1) return 1; // 回到起点,收敛条件 return getOrUpdate(x - 1, y) + getOrUpdate(x, y - 1); } int getOrUpdate(int x, int y) { if (f[x][y] > 0) { return f[x][y]; // 直接取用,避免重复计算 } else { return f[x][y] = dfs(x, y); } } };
Follow up for "Unique Paths": Now consider if some obstacles are added to the grids. How many unique paths would there be? An obstacle and empty space is marked as 1 and 0 respectively in the grid. For example, There is one obstacle in the middle of a 3x3 grid as illustrated below.
[ [0,0,0], [0,1,0], [0,0,0] ] The total number of unique paths is 2. Note: m and n will be at most 100.
题解分析:
此题只需要在 上一题的深度优先搜索中 加上一个 当前点为障碍时的 剪枝操作
class Solution { public: int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid) { // 0行和0列未用 int m = obstacleGrid.size(); int n = obstacleGrid.at(0).size(); this->f = vector<vector<int>>(m + 1, vector<int>(n+1, 0)); return dfs(obstacleGrid, m, n); } private: vector<vector<int>> f; // 缓存 int dfs(vector<vector<int>>& obstacleGrid, int x, int y) { if (x < 1 || y < 1) return 0; // 收据非法,终止条件 if (obstacleGrid[x - 1][y - 1] == 1) return 0; //为障碍 if (x == 1 && y == 1) return 1; // 回到起点,收敛条件 return getOrUpdate(obstacleGrid, x - 1, y) + getOrUpdate(obstacleGrid, x, y - 1); } int getOrUpdate(vector<vector<int>>& obstacleGrid, int x, int y) { if (f[x][y] > 0) { return f[x][y]; // 直接取用,避免重复计算 } else { return f[x][y] = dfs(obstacleGrid, x, y); } } };