當(dāng)前位置:
首頁 >
LeetCode题解
發(fā)布時(shí)間:2025/3/15
35
豆豆
生活随笔
收集整理的這篇文章主要介紹了
LeetCode题解
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
題目是這樣的: 一個(gè)機(jī)器人位于一個(gè) m x n 網(wǎng)格的左上角 (起始點(diǎn)在下圖中標(biāo)記為“Start” )。 機(jī)器人每次只能向下或者向右移動(dòng)一步。機(jī)器人試圖達(dá)到網(wǎng)格的右下角(在下圖中標(biāo)記為“Finish”)。 問總共有多少條不同的路徑?
輸出: 3
解釋:
從左上角開始,總共有 3 條路徑可以到達(dá)右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右 輸入: m = 7, n = 3
輸出: 28 這道題其實(shí)跟那個(gè)踩階梯的題很相似:“假如有10步臺階,一次可走一步或兩步,那么要走到達(dá)臺階頂,有幾種走法,我們都知道,這個(gè)是斐波那契問題,遞歸就可以了”。 我們可以這么解,假設(shè)最后一格是a[m][n],那么能到達(dá)a[m][n]的只有a[m-1][n]和a[m][n-1]。同理,要到達(dá)a[m-1][n],也只能從a[m-1-1][n]和a[m-1][n-1]; 要到達(dá)a[m][n-1],也只能從a[m-1][n-1]和a[m][n-1-1],這是個(gè)遞歸問題。直到a[i][j]中i=1或者j=1,當(dāng)i=1時(shí),就只可以能時(shí)從a[i][j-1]到達(dá),當(dāng)j=1時(shí),同樣,也只能從a[i-1][j]到達(dá); 于是,遞歸的邊界找到了。 可能上面說的不直觀,請看下面:
``` 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
有沒有發(fā)現(xiàn) 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) . . . . . ``` 于是我們很快想到了遞歸函數(shù)怎么寫: ``` 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); } ```
運(yùn)行一下:
結(jié)果對了,現(xiàn)在把參數(shù)值變大一點(diǎn):
時(shí)間還湊合,再變大,這次運(yùn)行時(shí)間有點(diǎn)久了:
超過了兩分鐘! 為什么呢,請看上面的發(fā)現(xiàn)那里:在我們計(jì)算r(9,4)的時(shí)候是不是中間會(huì)計(jì)算兩次r(8,3),并且r(8,4)和r(9,4)中間都會(huì)有r(7,4)的計(jì)算,而這些重復(fù)計(jì)算是很浪費(fèi)時(shí)間的。對這塊不了解的可以看這篇文章:https://mp.weixin.qq.com/s/llvtdxaPc29CNkcmtPHxKw 于是,為了避免重復(fù)計(jì)算,這個(gè)函數(shù)需要改寫,我們可以這樣,在計(jì)算r(8,3)的時(shí)候把r(8,3)的值保存起來,這樣下次計(jì)算r(8,3)的值的時(shí)候可以直接獲取,不需要再計(jì)算了,根據(jù)這個(gè)思路,把算法改良一下: ``` 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]; } ```
再看看運(yùn)行結(jié)果:
快了好多是不是!
例如:
輸入: m = 3, n = 2輸出: 3
解釋:
從左上角開始,總共有 3 條路徑可以到達(dá)右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右 輸入: m = 7, n = 3
輸出: 28 這道題其實(shí)跟那個(gè)踩階梯的題很相似:“假如有10步臺階,一次可走一步或兩步,那么要走到達(dá)臺階頂,有幾種走法,我們都知道,這個(gè)是斐波那契問題,遞歸就可以了”。 我們可以這么解,假設(shè)最后一格是a[m][n],那么能到達(dá)a[m][n]的只有a[m-1][n]和a[m][n-1]。同理,要到達(dá)a[m-1][n],也只能從a[m-1-1][n]和a[m-1][n-1]; 要到達(dá)a[m][n-1],也只能從a[m-1][n-1]和a[m][n-1-1],這是個(gè)遞歸問題。直到a[i][j]中i=1或者j=1,當(dāng)i=1時(shí),就只可以能時(shí)從a[i][j-1]到達(dá),當(dāng)j=1時(shí),同樣,也只能從a[i-1][j]到達(dá); 于是,遞歸的邊界找到了。 可能上面說的不直觀,請看下面:
``` 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
有沒有發(fā)現(xiàn) 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) . . . . . ``` 于是我們很快想到了遞歸函數(shù)怎么寫: ``` 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); } ```
運(yùn)行一下:
?
結(jié)果對了,現(xiàn)在把參數(shù)值變大一點(diǎn):
?
時(shí)間還湊合,再變大,這次運(yùn)行時(shí)間有點(diǎn)久了:
?
超過了兩分鐘! 為什么呢,請看上面的發(fā)現(xiàn)那里:在我們計(jì)算r(9,4)的時(shí)候是不是中間會(huì)計(jì)算兩次r(8,3),并且r(8,4)和r(9,4)中間都會(huì)有r(7,4)的計(jì)算,而這些重復(fù)計(jì)算是很浪費(fèi)時(shí)間的。對這塊不了解的可以看這篇文章:https://mp.weixin.qq.com/s/llvtdxaPc29CNkcmtPHxKw 于是,為了避免重復(fù)計(jì)算,這個(gè)函數(shù)需要改寫,我們可以這樣,在計(jì)算r(8,3)的時(shí)候把r(8,3)的值保存起來,這樣下次計(jì)算r(8,3)的值的時(shí)候可以直接獲取,不需要再計(jì)算了,根據(jù)這個(gè)思路,把算法改良一下: ``` 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]; } ```
再看看運(yùn)行結(jié)果:
?
快了好多是不是!
轉(zhuǎn)載于:https://www.cnblogs.com/aibaofeng/p/11098525.html
總結(jié)
以上是生活随笔為你收集整理的LeetCode题解的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 10 字符串相关操作
- 下一篇: HDU - 6183 Color it