1 描述
一个机器人在m×n大小的地图的左上角(起点)。
机器人每次可以向下或向右移动。机器人要到达地图的右下角(终点)。
可以有多少种不同的路径从起点走到终点?
示例1
输入:2,1
返回值:1
示例2
输入:2,2
返回值:2
2 方法一:递归(推荐使用)
int uniquePaths(int m, int n) {
//矩阵只要有一条边为1,路径数就只有一种了
if(m == 1 || n == 1)
return 1;
//两个分支: 向右走路径数 + 向下走路径数
return uniquePaths(m,n-1) + uniquePaths(m-1,n);
}
复杂度分析:
时间复杂度:O(mn),其中m、n分别为矩阵的两边长,递归过程对于每个m最多都要经过每一种nnn
空间复杂度:O(m+n),递归栈的最大深度为矩阵两边从m、n都到了1
3 方法二:组合数学(扩展思路)(复杂度最低)
//从矩阵左上角走到右下角,共需往下走m−1步,往右走n−1步,
//不同走法路径在于往下和往右的组合情况,即在一堆往下和往右的序列中,每种排列的情况;
//序列一共有(m-1)+(n-1) = m+n−2个位置,即每条路径都要走 m+n−2步才能到达终点
//选择n−1个位置作为往右,即不同的走法有{m+n−2,n−1}=(m+n-2)(m+n-3)(m+n-4)…(m-1)/(n-1)!
// =(m+n-2)!/[(n-1)!(m-1)!];;;;例如{5,3}=543/3! = 5!/[3!(5-3)!]
int uniquePaths(int m, int n) {
long res = 1;
//①选择往右走为主的组合 n−1
for(int i = 1; i < n; i++)
res = res * (m-1+i) / i ; // (m-1+1)*(m-1+2)*...*(m-1+(n-1))/(n-1)!
return (int)res;
}
//②选择往下走为主的组合 m−1
for(int i = 1; i < m; i++)
res = res * (n-1+i) / i ; // (n-1+1)*(n-1+2)*...*(n-1+(m-1))/(m-1)!
复杂度分析:
时间复杂度:O(n),计算过程需要从1遍历到n
空间复杂度:O(1),常数级变量,无额外辅助空间
4 方法三:动态规划(扩展思路)
//方法三:动态规划
//dp[i][j]表示大小为i*j的矩阵的路径数量
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
for(int i = 1; i <= m; i++){
for(int j = 1; j <= n; j++){
if(i == 1 || j == 1){//只有一行或一列,路径只有一条
dp[i][j] = 1;
continue;
}
//路径数等于左方格子的路径数加上上方格子的路径数
dp[i][j] = dp[i][j - 1] + dp[i - 1][j];
}
}
return dp[m][n];
}
复杂度分析:
时间复杂度:O(mn),其中m、n分别为矩阵的两边长,两层遍历填充整个dp数组
空间复杂度:O(mn),辅助空间dp数组为二维数组