[剑指offer] 矩形覆盖

题目描述

我们可以用2*1的小矩形横着或者竖着去覆盖更大的矩形。请问用n个2*1的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

输入描述

一个大矩形

输出描述

覆盖的方法数

题目分析

设 被n个2*1的小矩形无重叠地覆盖的方法总数为 f(n)

  • 当n=1时,明显f(1)=1;

  • 当n=2时,只能两个都横着或两个都竖着放,有f(2)=2;

  • 当小矩形个数为n,来覆盖这个2*n的大矩形。第一步只有两种放法:

     ①竖着放,那么剩下的摆放总数为 f(n-1)

[剑指offer] 矩形覆盖_第1张图片 

   ②横着放,那么剩下的摆放总数为 f(n-2)。因为它下面的那块也跟随着它的摆放而确定(必须是一个横着放的小矩形)。

 

很容易看出满足斐波那契数列。

斐波那契数列(Fibonacci sequence),又称黄金分割数列

在数学上,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2,n∈N*)  

指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、…… 

可以得出递推公式:

     | 1     (n=0 )
f(n) =   | 1      (n=1 )
     | f(n-1)+f(n-2)  (n>=2)

解法一 (递归)  运行时间:924ms  占用内存:654k

public class Solution {
    public int RectCover(int target) {
        if(target<=1) return 1;
        return RectCover(target-1)+RectCover(target-2);
    }
}

递归效率不高,重复计算多,比如:

f(4) = f(3) + f(2);
      = f(2) + f(1) + f(1) + f(0);       = f(1) + f(0) + f(1) + f(1) + f(0);

求f(4)就要计算三次f(1)和两次f(0),显然这是不行的。

解法二(动态规划)  运行时间:29ms 占用内存:629k

public class Solution {
    public int RectCover(int target) {
        if(target<=1) return 1;
        int i =1;//f(0)
        int j =1;//f(1)
        for(;target>=2;target--){
            j+=i;
            i=j-i;
        }
        return j;
    }
}

显然这个快很多,n>=2时,根据 f(n)=f(n-1)+f(n-2)进行依次计算,最后得出 f(target)并返回。

你可能感兴趣的:(矩形覆盖,剑指offer)