LeetCode 题解:Unique Path

题目描述


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:

  1. Right -> Right -> Down
  2. Right -> Down -> Right
  3. Down -> Right -> Right
    Example 2:

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%的提交

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章