赞
踩
一个机器人位于一个 m x n
网格的左上角 (起始点在下图中标记为 Start
)。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 Finish
)。问总共有多少条不同的路径?
示例1:
输入: m = 3, n = 7
输出: 28
示例2:
输入: m = 3, n = 2
输出: 3
解释: 从左上角开始,总共有 3 条路径可以到达右下角。
1.向右 -> 向右 -> 向下
2.向右 -> 向下 -> 向右
3.向下 -> 向右 -> 向右
示例3:
输入: m = 7, n = 3
输出: 28
示例4:
输入: m = 3, n = 3
输出: 6
提示:
1 <= m, n <=100
2 * 10^9
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths
读完题目思考片刻,确定这是一道递归的题。定义状态 count(m,n)
表示当矩形是 m x n
网格时从左上到右下的路径数,由于每次只可以往下走和往右走,故 count(m,n) = count(m,n-1) + count(m-1,n)
此时的行数和列数都要大于 1
,当 m == 1
或 n == 1
时 count(m,n) = 1
是我们的递归出口。
public 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); // 递归
}
}
代码执行结果超出时间限制,因为计算 uniquePaths(m,n) 时会先去计算 uniquePaths(m-1,n) 和uniquePaths(m,n-1),之后由会一层一层往下去计算,知道碰到递归出口才有结果,并再将结果一层一层的往回传,故时间消耗很大。这也是自顶向下的递归解题
由于上面的递归时间消耗太大,我们就改变策略自底向上的计算结果,并将结果保留在如下二维数组 result
中,当所处的位置和终点位于同一行或同一列时,就只能直接沿直线走到终点,所以这些位置都是 1
种路径,如图的绿色位置,由于每次走都只能往下或右走,故当前位置的路径数取决于下面位置与右边位置的路径之和,即 result[i][j] = result[i+1][j] + result[i][j+1]
并且我们的填表顺序也有要求,必须是当前位置下方和右方的都已经填好,才能填当前位置。我们可以按照下图中细箭头的方向向上填表,同时沿着粗箭头向左填表,填完表后返回 result[0][0]
即为最终结果。
public class Solution {
public int uniquePaths(int m, int n) {
int[][] result = new int[m][n]; // 定义结果表
for (int i = 0;i<n;i++) result[m-1][i] = 1; // 初始化最后一行为1
for (int i = 0;i<m;i++) result[i][n-1] = 1; // 初始化最后一列为1
for (int i = n-2;i>=0;i--){ // 列从右往左填
for (int j = m-2;j>=0;j--){ // 行从下往上填
result[j][i] = result[j+1][i]+result[j][i+1]; // 当前位置等于下面和右边之和
}
}
return result[0][0]; // 返回起点结果
}
}
时间上完胜,空间效果也不错,做完后也去看看了题解,一方面看看自己思考的结论对不对(主要看上面的方法是不是递归和动态规划,其实有的时候还傻傻的分不太清)另一方面就是看看有没有改进的地方,看到空间上还有提升的空间,主要是我们刚刚定义的结果二维数组并不是都有用的在计算结果的时候只需要保留部分就好,这里我实在是懒得再去优化了,不是很难,想尝试的朋友可以写写看。
其次看到还有一种解题思路是通过数学公式的方法,这里也只简单介绍一下:我们要想到达终点,需要往下走n-1步,往右走m-1步,总共需要走n+m-2步。他无论往右走还是往下走他的总的步数是不会变的。也就相当于总共要走n+m-2步,往右走m-1步总共有多少种走法,很明显这就是一个排列组合问题,公式如下
public int uniquePaths(int m, int n) {
int N = n + m - 2;
double res = 1;
for (int i = 1; i < m; i++)
res = res * (N - (m - 1) + i) / i;
return (int) res;
}
这里推荐着重理解动态规划和递归的解题思路,虽然这个题的递归超时了,但很多题目里递归也是一种很好的解题思路。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。