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

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