題目是這樣的:
一個機器人位於一個 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(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];
}
```
再看看運行結果:
快了好可能是不是!