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.
解:1:从左上角走到右下角需要向下移动m-1步,向右移动n-1步。每次移动前,判断是否还能向下或者向右移动。在向下或者向右移动一步后,接下来的移动过程可以递归调用。
class Solution { public: int uniquePaths(int m, int n) { int i = m, j = n; int res = 0; if (i <= 1 || j <= 1) { res += 1; return res; } else if (i > 1 && j > 1) res += uniquePaths(i - 1, j) + uniquePaths(i, j - 1); else if (i > 1 && j <= 1) res += uniquePaths(i - 1, j); else if (i <= 1 && j > 1) res += uniquePaths(i, j - 1); } };
换个思路考虑,如果某次移动到了最下行或者最右行,则接下来的移动没有选择,只有一条路径了。因此可以改进程序如下所示:
class Solution { public: int uniquePaths(int m, int n) { if(m == 1 || n == 1) return 1; else return uniquePaths(m - 1, n) + uniquePaths(m, n - 1); } };
因为递归调用,在m,n较大时会出现Time Limit Exceeded。
解法2:从左上角走到右下角需要向下移动m-1步,向右移动n-1步,一共移动m+n-2步。因为中间没有任何障碍,所以很简单:即是在m+n-2步中取m-1步向下,或者是在m+n-2步中取n-1步向右即可。即是求组合数C(m+n-2,m-1)或者C(m+n-2,n-1)。因为m+n-2=m-1+n-1,假设n>m,则C(m+n-2,m-1)=(m+n-2)*(m+n-3)*...*n/(m-1)!。
class Solution { public: int uniquePaths(int m, int n) { int res = 0; int a = m > n ? m : n; int b = m + n - a - 1; int sum = m + n - 2; long long p1 = 1, p2 = 1; while (sum >= a) p1 = p1 * sum--; while (b >= 1) p2 = p2 * b--; res = p1 / p2; return res; } };
解法3:动态规划。移动到[i,j]的路径path[i,j]=path[i-1,j]+path[i,j-1](0<i<m,0<j<n),初始化path[i][0]=1,path[0][j]=1(0<=i<m,0<=j<n)。最后path[m-1][n-1]即是最终结果。时间空间复杂度都是O(mn)。
class Solution { public: int uniquePaths(int m, int n) { int res = 0; if(m <= 0 || n <= 0) return res; int** path = new int*[m]; for(int i = 0; i < m; i++) path[i] = new int[n]; for(int i = 0; i < m; i++) path[i][0] = 1; for(int i = 0; i < n; i++) path[0][i] = 1; for(int i = 1; i < m; i++) { for(int j = 1; j < n; j++) path[i][j] = path[i - 1][j] + path[i][j - 1]; } res = path[m - 1][n - 1]; for(int i = 0; i < m; i++) delete[] path[i]; delete[] path; return res; } };
利用滚动数组可以将空间复杂度降为O(n):
class Solution { public: int uniquePaths(int m, int n) { int res = 0; if(m <= 0 || n <= 0) return res; int* path = new int[n]; for(int i = 0; i < n; i++) path[i] = 1; for(int i = 1; i < m; i++) { for(int j = 1; j < n; j++) path[j] += path[j - 1]; } res = path[n - 1]; delete[] path; return res; } };
外层循环使得path保存了移动到当前行的上一行所有位置的路径数目,因此内层循环只需要在加上当前列的左边列的路径数目即可。