動態規划法面試題(一):矩形覆蓋


關於矩形覆蓋面試題

  之前已經在上一篇分治法面試題(一):矩形覆蓋一文中給出了該問題的遞歸解法。但是上面的分析可以看出效率不高,主要是存在大量重復元素的計算。那么如何避免大量重復元素的計算呢?這里將給出幾種解決方案。

關於動態規划

  動態規划的思想與我們上篇探討的分治法相似,也是通過組合子問題的解從而得到整個問題的解。從上節給出的題目看得出來,分治分解出的子問題都是相對獨立的,但是動態規划分解的子問題通常不是獨立存在的。分治法有時候存在分解后的問題太多,因而重復計算也多的問題。那么如果能夠保存已求得的子問題的答案,從而在再次使用的時候調出,就會節省大量的時間。我們可以用一個表(數組)來存放求得的子問題的解,這就是動態規划的思想。

  下面就給出集中解決方案,題目仍采用上篇所述的矩形覆蓋。

解決方案1

class Solution {
public:
    int a[1000];//采用動態數組更好,此處僅作演示
    int rectCover(int number) {
        if(a[number]!=0)
            return a[number];
        if(number<=0) return 0;
        if(number==1) a[number]=1;
        else if(number==2) a[number]=2;
        else
            {
            int p=rectCover(number-1);
            int q=rectCover(number-2);
            a[number]=p+q;
        }
        return a[number];
    }
};

  該解法稱為動態規划的“備忘錄”法,即帶備忘的自頂向下法。感興趣的可以拿上篇分析的rectCover(5)來試試,rectCover(1),rectCover(2)都只需要計算一次。即如果該元素已經被計算過了,那就直接“取”。

解決方案2

 1 class Solution {
 2 //自底向上
 3 public:
 4     int a[1000];
 5     int rectCover(int number) {
 6        a[1]=1;
 7         a[2]=2;
 8         for(int i=3;i<=number;i++)
 9             a[i]=a[i-1]+a[i-2];
10         return a[number];;
11     }
12 };

  事實上,解法一是動態規划的變形形式,動態規划一般的都是自底向上求解,如解法2。

解決方案3

 

 1 class Solution {
 2 public:
 3     int rectCover(int number) {
 4       if(number<=0) return 0;
 5         if(number==1) return 1;
 6         if(number==2) return 2;
 7         int num1=1;
 8         int num2=2;
 9         int result=0;
10         number=number-2;
11         while(number--){
12             result=num1+num2;
13             num1=num2;
14             num2=result;
15         }
16         return result;
17     }
18 };

  解決方案3的最大的優勢是不需要額外的數組來存放元素。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM