劍指offer 動畫圖解 | 矩形覆蓋 用遞歸的思路解題

通過刷題劍指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;
}

至於爲什麼遞歸效率比較差,讀者們可以參考我們之前的斐波那契數列的分析文章,裏面有關於遞歸方面題目的分析,值得一讀。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章