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 7 x 3 grid. How many possible unique paths are there?
Note: m and n will be at most 100.
Example 1:
Input: m = 3, n = 2
Output: 3
Explanation:
From the top-left corner, there are a total of 3 ways to reach the bottom-right corner:
Input: m = 7, n = 3
Output: 28
有一个m*n的矩阵,有一个机器人在矩阵中移动,起点是左上角,终点是右下角,每次只能移动一步并且只能向右边或者左边移动,请问一共有多少种不同的移动方式。
在矩阵中移动,我们第一感觉肯定是深度优先搜索,我们每次移动一步——向右或者向左,到终点的时候路径数+1,保证不重我们用一个visited数组记录走过的位置。
代码如下:
/**
* @param {number} m
* @param {number} n
* @return {number}
*/
var uniquePaths = function(m, n) {
var visited = new Array(m);
for(var i = 0;i < m;i++) visited[i] = new Array(n);
return recursive(0,0,m,n,visited);
};
function recursive(x,y,m,n,visited){
if(x==m-1&&y==n-1) return 1;
var res = 0;
visited[x][y] = true
if(x+1 < m && !visited[x+1][y]) res+= recursive(x+1,y,m,n, visited);
if(y+1 < n && !visited[x][y+1]) res+= recursive(x,y+1,m,n,visited);
visited[x][y] = false;
return res
}
输入3 2,7 3,输出了正确结果,输入20 20,发现超时了。导致超时的原因是什么呢?通过观察我们发现,这种解法有大量的重复计算,例如7 3,我们对于点(1,1),我们走(1,0)向下会计算(1,1)到终点的路径数,走(0,1)向右会计算(1,1)到终点的路径数,这时其实从(1,1)到终点的路径数是固定的,只需要计算一次就可以了。所以我们做一些优化,当第一次计算出(1,1)的时候,我们将结果缓存下来,下一次就不需要计算了。代码如下:
/**
* @param {number} m
* @param {number} n
* @return {number}
*/
var uniquePaths = function(m, n) {
var visited = new Array(m);
for(var i = 0;i < m;i++) visited[i] = new Array(n);
return recursive(0,0,m,n,visited);
};
function recursive(x,y,m,n,visited){
if(x==m-1&&y==n-1) return 1;
var res = 0;
if(x+1 < m && !visited[x+1][y]) res+= recursive(x+1,y,m,n, visited);
else if(x+1 < m &&visited[x+1][y]) res+= visited[x+1][y];
if(y+1 < n && !visited[x][y+1]) res+= recursive(x,y+1,m,n,visited);
else if(y+1 <n &&visited[x][y+1]) res+= visited[x][y+1];
visited[x][y] = res;
return res
}
提交代码,发现ac了,超越了60%的提交,那么我们是不是还可以进一步优化呢?能不能把递归的转成递推的呢?
这其实就是动态规划的思想了,我们记录中间状态,然后将由中间状态计算出下一个状态,直到得到最后的结果。这样可以避免很多重复计算。
动态规划有几个关键要素,状态和状态转移方程以及边界条件。这里我们的状态(i,j)代表从点(i,j)到终点的路径数,(i,j)=(i+1,j)+(i,j+1),边界是最下和最右的两列,(m-1,i)=1,(i,n-1)=1.
代码如下:
/**
* @param {number} m
* @param {number} n
* @return {number}
*/
var uniquePaths = function(m, n) {
var visited = new Array(m);
for(var i = 0;i < m;i++) visited[i] = new Array(n);
for(i=0;i < n;i++) visited[m-1][i] = 1;
for(i = 0;i <m;i++) visited[i][n-1] = 1;
for(i=m-2;i>=0;i--){
for(var j = n-2;j>=0;j--){
visited[i][j] = visited[i+1][j]+visited[i][j+1];
}
}
return visited[0][0]
};
注意从后向前遍历,处理好边界条件,超过100%的提交