【剑指offer - C++/Java】10、矩形覆盖
在線題目鏈接:矩形覆蓋
文章目錄
- 1 題目描述
- 2 題目分析
- 3 代碼
- 3.1 遞歸方法
- 3.11 Java代碼
- 3.12 C++代碼
- 3.2 動態規劃算法
- 3.2 動態規劃
- 3.21 Java代碼
- 3.22 C++代碼
- 3.3 循環方法
- 3.31 Java代碼
- 3.32 C++代碼
- 4、總結
1 題目描述
我們可以用2*1的小矩形橫著或者豎著去覆蓋更大的矩形。請問用n個2*1的小矩形無重疊地覆蓋一個2*n的大矩形,總共有多少種方法?
2 題目分析
乍一看感覺無從下手!!!其實如果我們使用歸納方法的話,總能夠總結出規律來。
假設下面是一個2*n的大矩形:
我們要使用下面這樣的2*1的小矩形來填滿上述的大矩形:
我們假設將2*n的矩形填滿需要f(n)種方法
那么填充的方法可以有下面的兩種方法:
很明顯,到這里我們就可以列出一個公式:
- f(n)=f(n-1)+f(n-2)
這個公式我們太熟悉了,這就是斐波那契數列,我們看下面三篇文章的算法題都是這個公式的應用:
- 斐波那契數列
- 跳臺階
- 變態跳臺階
綜上以及題目要求,我們得出綜合公式(n=0時f(n)=0):
由此可以寫出三種不同的代碼:遞歸,動態規劃,循環
3 代碼
3.1 遞歸方法
遞歸方法很簡單,直接利用公式即可。
3.11 Java代碼
public class Solution {public int RectCover(int target) {//遞歸if(target<3)return target;return RectCover(target-1)+RectCover(target-2);} }3.12 C++代碼
class Solution { public:int rectCover(int number) {//遞歸if(number<3)return number;return rectCover(number-1)+rectCover(number-2);} };我們都知道這種遞歸解法會有很多重復的計算,就像下面的,假設我們要計算f(10):
計算f(10),要重復計算兩次f(8),三次f(7),三次f(6),這種重復計算,對于數據比價大的時候,開銷是非常大的。所以我們經常說,遞歸雖然好寫,但是不建議在實現算法的時候使用遞歸算法。
3.2 動態規劃算法
3.2 動態規劃
凡是能用遞歸寫出的代碼,一定能夠用動態規劃寫出來。
我們知道遞歸是為了求某一個值,而必須先知道另外的幾個值后才能求出來。而想要求那另外的幾個值,還需要再求另外的另外的值,就像上面的遞歸二叉樹,想要先求f(10),必須知道f(9)和發(8)。想要知道f(9)又得知道f(8)和f(7)…
上面遞歸是想要計算總體值,需要求局部的值,想要求局部的值,又要求局部的局部的值。
動態規劃不是這樣,動態規劃是先從遞歸的終止條件開始計算,也就是說,動態規劃先計算局部的值,然后根據局部的值的累積,最終得到整體要求的值。也就是與遞歸反過來了。
比如針對上面的求f(10),我們先求f(1),f(2),f(3)…最終肯定會求得f(10)。這樣我們就沒有進行重復的計算。每一項都是只計算一次。
看代碼就能明白上面說的是什么意思了。下面的ret數組,ret[i]代表斐波那契數組的第i項。我們要求得第n項,最后求到ret[n]直接返回即可。
3.21 Java代碼
public class Solution {public int RectCover(int target) {//這同樣是斐波那契數列 f(n)=f(n-1)+f(n-2)//動態規劃if(target<=2)return target;int[] ret=new int[target+1];ret[1]=1;ret[2]=2;int i;for(i=3;i<=target;i++){ret[i]=ret[i-1]+ret[i-2];}return ret[target];} }3.22 C++代碼
class Solution { public:int rectCover(int number) {//這同樣是斐波那契數列 f(n)=f(n-1)+f(n-2)//動態規劃//if(number<=2)return number;int ret[number+1];ret[0]=0;ret[1]=1;ret[2]=2;int i;for(i=3;i<=number;i++){ret[i]=ret[i-1]+ret[i-2];}return ret[number];} };3.3 循環方法
所有的遞歸都可以寫成動態規劃,同理所有的動態規劃,也一定能寫成循環。只不過有的動態規劃不好寫成循環而已。本題是非常好寫成循環的。
循環比動態規劃好的原因在于,循環只用幾個變量,循環使用它們得到最終結果,不保存之前的計算結果,動態規劃卻需要開辟一個數組,將所有計算過的結果保存,這很浪費空間。
3.31 Java代碼
public class Solution {public int RectCover(int target) {//循環if(target<3)return target;int r1=1,r2=2,ret=0;int i;for(i=3;i<=target;i++){ret=r1+r2;r1=r2;r2=ret;}return ret;} }當然,上面使用三個變量,我們還可以再減少一個變量,使用兩個變量:
public class Solution {public int RectCover(int target) {//循環,更加單的寫法if(target<3)return target;int r1=1,r2=2;int i;for(i=3;i<=target;i++){r2+=r1;r1=r2-r1;}return r2;} }3.32 C++代碼
三個變量
class Solution { public:int rectCover(int number) {//循環if(number<3)return number;int r1=1,r2=2,ret=0;int i;for(i=3;i<=number;i++){ret=r1+r2;r1=r2;r2=ret;}return ret;} };兩個變量
class Solution { public:int rectCover(int number) {//循環,更加單的寫法if(number<3)return number;int r1=1,r2=2;int i;for(i=3;i<=number;i++){r2+=r1;r1=r2-r1;}return r2;} };4、總結
注意學會遞歸,動態規劃,循環三者時間的關系
探討學習加:
個人qq:1126137994
個人微信:liu1126137994
總結
以上是生活随笔為你收集整理的【剑指offer - C++/Java】10、矩形覆盖的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 在线浏览 Stata 15 PDF 全套
- 下一篇: intel rst linux 驱动下载