LeetCode題解

題目是這樣的:
一個機器人位於一個 m x n 網格的左上角 (起始點在下圖中標記爲「Start」 )。
機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記爲「Finish」)。
問總共有多少條不一樣的路徑?
 
 

例如:算法

輸入: m = 3, n = 2
輸出: 3
解釋:
從左上角開始,總共有 3 條路徑能夠到達右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
 
 
 
輸入: m = 7, n = 3
輸出: 28
 
 
  這道題其實跟那個踩階梯的題很類似:「假若有10步臺階,一次可走一步或兩步,那麼要走到達臺階頂,有幾種走法,咱們都知道,這個是斐波那契問題,遞歸就能夠了」。
  咱們能夠這麼解,假設最後一格是a[m][n],那麼能到達a[m][n]的只有a[m-1][n]和a[m][n-1]。同理,要到達a[m-1][n],也只能從a[m-1-1][n]和a[m-1][n-1];
要到達a[m][n-1],也只能從a[m-1][n-1]和a[m][n-1-1],這是個遞歸問題。直到a[i][j]中i=1或者j=1,當i=1時,就只能夠能時從a[i][j-1]到達,當j=1時,一樣,也只能從a[i-1][j]到達;
因而,遞歸的邊界找到了。
  可能上面說的不直觀,請看下面:

```
           r(m,3)的值       r(m,4)的值   r(m,4)-r(m-1,4)的差值

            r(1,3)=1         r(1,4)=1         3
            r(2,3)=3         r(2,4)=4         6 
            r(3,3)=6         r(3,4)=10       10
            r(4,3)=10        r(4,4)=20       15  
            r(5,3)=15        r(5,4)=35       21  
            r(6,3)=21        r(6,4)=56       28  
            r(7,3)=28        r(7,4)=84       36  
            r(8,3)=36        r(8,4)=120      45  
            r(9,3)=45        r(9,4)=165

        有沒有發現
        r(9,4)=r(8,4)+45=r(8,4)+r(9,3)=r(7,4)+r(8,3)+r(8,3)+r(9,2)
        r(8,4)=r(7,4)+36=r(7,4)+r(8,3)=r(6,4)+r(7,3)+r(7,3)+r(8,2)
        .
        .
        .
        .
        .
```
因而咱們很快想到了遞歸函數怎麼寫:
```
    public int uniquePaths2(int m, int n) {
        if (m == 1) {
        return 1;
        }
        if (n == 1) {
        return 1;
        }
        return uniquePaths2(m - 1, n) + uniquePaths2(m, n - 1);
    }
```

運行一下:

 

 


結果對了,如今把參數值變大一點:

 


時間還湊合,再變大,此次運行時間有點久了:

 


超過了兩分鐘!
爲何呢,請看上面的發現那裏:在咱們計算r(9,4)的時候是否是中間會計算兩次r(8,3),而且r(8,4)和r(9,4)中間都會有r(7,4)的計算,而這些重複計算是很浪費時間的。對這塊不瞭解的能夠看這篇文章: https://mp.weixin.qq.com/s/llvtdxaPc29CNkcmtPHxKw
因而,爲了不重複計算,這個函數須要改寫,咱們能夠這樣,在計算r(8,3)的時候把r(8,3)的值保存起來,這樣下次計算r(8,3)的值的時候能夠直接獲取,不須要再計算了,根據這個思路,把算法改良一下:
```
public int uniquePaths3(int m, int n) {
        int[][] all = new int[m][n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (i == 0 || j == 0) {
                    all[i][j] = 1;
                } else {
                    all[i][j] = all[i - 1][j] + all[i][j - 1];
                }
            }
        }
        return all[m - 1][n - 1];
}
```

再看看運行結果:

 


快了好可能是不是!
相關文章
相關標籤/搜索