力扣62-不同路徑(動態規劃,遞迴,數學公式多方法比較 Java題解)
技術標籤:演算法刷題動態規劃java演算法leetcode遞迴演算法
力扣62-不同路徑
一、原題題目
1.1 題目
一個機器人位於一個 m x n
網格的左上角 (起始點在下圖中標記為 Start
)。機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為 Finish
)。問總共有多少條不同的路徑?
![題目示圖](https://img.796t.com/res/2020/12-26/16/812a98b294502948126450edff6054d7.jpg)
1.2 示例
-
示例1:
輸入:
m = 3, n = 7
輸出:28
-
示例2:
輸入:
m = 3, n = 2
輸出:3
解釋: 從左上角開始,總共有 3 條路徑可以到達右下角。
1.向右 -> 向右 -> 向下
2.向右 -> 向下 -> 向右 -
示例3:
輸入:
m = 7, n = 3
輸出:28
-
示例4:
輸入:
m = 3, n = 3
輸出:6
提示:
1 <= m, n <=100
- 題目資料保證答案小於等於
2 * 10^9
來源:力扣(LeetCode)
連結:https://leetcode-cn.com/problems/unique-paths
二、解題思路
2.1 遞迴思路解題
- 解題思路
讀完題目思考片刻,確定這是一道遞迴的題。定義狀態 count(m,n)
表示當矩形是 m x n
網格時從左上到右下的路徑數,由於每次只可以往下走和往右走,故 count(m,n) = count(m,n-1) + count(m-1,n)
1
,當 m == 1
或 n == 1
時 count(m,n) = 1
是我們的遞迴出口。
- 詳細程式碼(Java)
public class Solution {
public int uniquePaths(int m, int n) {
if (m == 1||n==1) return 1; // 遞迴出口
else return uniquePaths(m-1,n)+uniquePaths(m,n-1); // 遞迴
}
}
- 程式碼執行結果
![遞迴執行結果](https://img.796t.com/res/2020/12-26/16/7b8f4c42a9af4963d1e185c9449fb228.jpg)
程式碼執行結果超出時間限制,因為計算 uniquePaths(m,n) 時會先去計算 uniquePaths(m-1,n) 和uniquePaths(m,n-1),之後由會一層一層往下去計算,知道碰到遞迴出口才有結果,並再將結果一層一層的往回傳,故時間消耗很大。這也是自頂向下
2.1 動態規劃思路解題
- 解題思路
由於上面的遞迴時間消耗太大,我們就改變策略自底向上的計算結果,並將結果保留在如下二維陣列 result
中,當所處的位置和終點位於同一行或同一列時,就只能直接沿直線走到終點,所以這些位置都是 1
種路徑,如圖的綠色位置,由於每次走都只能往下或右走,故當前位置的路徑數取決於下面位置與右邊位置的路徑之和,即 result[i][j] = result[i+1][j] + result[i][j+1]
並且我們的填表順序也有要求,必須是當前位置下方和右方的都已經填好,才能填當前位置。我們可以按照下圖中細箭頭的方向向上填表,同時沿著粗箭頭向左填表,填完表後返回 result[0][0]
即為最終結果。
![動態規劃圖解](https://img.796t.com/res/2020/12-26/16/33b730157251f015550765c5d1048067.jpg)
- 詳細程式碼(Java)
public class Solution {
public int uniquePaths(int m, int n) {
int[][] result = new int[m][n]; // 定義結果表
for (int i = 0;i<n;i++) result[m-1][i] = 1; // 初始化最後一行為1
for (int i = 0;i<m;i++) result[i][n-1] = 1; // 初始化最後一列為1
for (int i = n-2;i>=0;i--){ // 列從右往左填
for (int j = m-2;j>=0;j--){ // 行從下往上填
result[j][i] = result[j+1][i]+result[j][i+1]; // 當前位置等於下面和右邊之和
}
}
return result[0][0]; // 返回起點結果
}
}
- 程式碼執行結果
![動態規劃執行結果](https://img.796t.com/res/2020/12-26/16/fc3ab2fe4faf87880233f1c222ad62bb.jpg)
時間上完勝,空間效果也不錯,做完後也去看看了題解,一方面看看自己思考的結論對不對(主要看上面的方法是不是遞迴和動態規劃,其實有的時候還傻傻的分不太清)另一方面就是看看有沒有改進的地方,看到空間上還有提升的空間,主要是我們剛剛定義的結果二維陣列並不是都有用的在計算結果的時候只需要保留部分就好,這裡我實在是懶得再去優化了,不是很難,想嘗試的朋友可以寫寫看。
2.3 數學公式思路解題
- 解題思路
其次看到還有一種解題思路是通過數學公式的方法,這裡也只簡單介紹一下:我們要想到達終點,需要往下走n-1步,往右走m-1步,總共需要走n+m-2步。他無論往右走還是往下走他的總的步數是不會變的。也就相當於總共要走n+m-2步,往右走m-1步總共有多少種走法,很明顯這就是一個排列組合問題,公式如下
- 詳細程式碼(Java)
public int uniquePaths(int m, int n) {
int N = n + m - 2;
double res = 1;
for (int i = 1; i < m; i++)
res = res * (N - (m - 1) + i) / i;
return (int) res;
}
- 程式碼執行結果
![數學技巧執行結果](https://img.796t.com/res/2020/12-26/16/a890796e509565c35080f6af46944b1a.jpg)
三、總結
這裡推薦著重理解動態規劃和遞迴的解題思路,雖然這個題的遞迴超時了,但很多題目裡遞迴也是一種很好的解題思路。