(今天开始用中文的算了,服务器好一些,之前美国的老连不上)
题目:
机器人位于一个 m x n 网格的左上角, 在下图中标记为“Start” (开始)。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角,在下图中标记为“Finish”(结束)。
问有多少条不同的路径?
例如,上图是一个3 x 7网格。有多少可能的路径?
注意: m 和 n 的值均不超过 100。
思路:
第一反应是递归,如何递归?比如每个格子能够走到终点的路径数 = 从当前格子右边的格子开始的路径数 + 从当前格子下边的格子开始的路径数。所以可以以此为条件进行递归,然后递归的终止条件是,某一行或者某一列只有一格,这种时候其路径数只有一条,这个时候跳出就行了。
但是!!!这样做的一个问题是,势必有的格子会重复计算,比如说原题目中,小机器人所在格的右下格,这个格子在递归中,被计算了两次(分别是其上面的格子和左边的格子)。
回想一下用递归的方式计算斐波拉契数列,其时间复杂度是O(2^N),当N越来越大的时候,消耗的时间会指数增大。因此递归实现这个问题也是同理,用递归实现了一下,果不其然,结果显示超时。
那么什么样的方式比较好?想一下斐波拉契数的解决方式:从0和1开始,逐步往上走。其实这个问题也可以看作是一个逐步往上走的过程。因为每一个格子的路径数上面也已经交代了, 之前的思路是要求哪个格子,就从这个格子出发往下层计算。现在颠倒一下,先求好下层的路径数,需要求哪个格子的路径数,根据上述计算公式直接加起来即可。
因此我们构建一个二维数组来存储每个格子的路径数,从终点处开始向上推。如果碰到某行或者某列是1的情况,那么路径数就直接为1,否则,该格子的路径数等于其下面的格子路径数加上其右边的格子的路径数。
代码:
class Solution {
public int uniquePaths(int m, int n) {
int[][] nums = new int[m][n];
for (int i = 0 ;i < m;i++) {
for (int j = 0; j < n; j++) {
if(i == 0 || j == 0)
nums[i][j] = 1;
else
nums[i][j] = nums[i - 1][j] + nums[i][j - 1];
}
}
return nums[m - 1][n - 1];
}
}
这样做的话,时间复杂度只有O(mn)。