通過刷題劍指offer,可以有效提升面試的成功率,這是因爲技術崗位的面試總是離不開算法題。如果想要在算法題方面表現得好的話,刷題是唯一的捷徑。
正所謂:書山有路勤爲徑
題目描述
我們可以用2x1的小矩形橫着或者豎着去覆蓋更大的矩形。請問用n個2x1的小矩形無重疊地覆蓋一個2xn的大矩形,總共有多少種方法?
比如n=3時,2x3的矩形塊有3種覆蓋方法:
解題思路
這一題可以用遞歸的思想來解決。首先我們先來看看幾個基本情況下,有幾種覆蓋方法。
從圖中可以看到,當 n = 1 的時候,我們有一種覆蓋方法,當 n = 2 的時候,我們有兩種覆蓋方法。
這個時候我們可以運用遞歸的思維,思考當 n + 1 的時候會發生什麼事情?
由上圖可見,當我們要嘗試覆蓋多出來的一塊 2x1 區域時,我們可以有兩種擺法,分別是豎着擺放一塊 2x1 的矩形,或是橫着擺放兩塊 2x1 的矩形,而這分別又取決於 n 與 n - 1 的覆蓋方法。
因此我們可以得出結論:
f(n+1) = f(n) + f(n-1)
算法
根據公式:
f(n+1) = f(n) + f(n-1)
可以看出來這是一個遞歸公式。因此我們可以直接寫一個遞歸函數
// 遞歸效率: O(2^n) 效率不理想
public int RectCover(int target) {
if (target == 0) {
return 0;
} else if (target == 1) {
return 1;
} else if (target == 2) {
return 2;
}
return RectCover(target - 1) + RectCover(target - 2);
}
然而該遞歸函數的效率不是很理想,我們可以改成循壞的方法來改進算法的效率。
// 循環效率: O(n) 效率理想
public int RectCover(int target) {
if (target == 0) {
return 0;
} else if (target == 1) {
return 1;
} else if (target == 2) {
return 2;
}
int temp1 = 1;
int temp2 = 2;
int result = 0;
for (int i = 2; i < target; i++) {
result = temp1 + temp2;
temp1 = temp2;
temp2 = result;
}
return result;
}
至於爲什麼遞歸效率比較差,讀者們可以參考我們之前的斐波那契數列的分析文章,裏面有關於遞歸方面題目的分析,值得一讀。