【JZ70 矩形覆盖】

描述

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

数据范围: 0 ≤ n ≤ 38
进阶:空间复杂度 O(1) ,时间复杂度 O(n)

注意:约定 n == 0 时,输出 0

比如 n=3 时,2 * 3 的矩形块有3种不同的覆盖方法(从同一个方向看):

在这里插入图片描述
输入描述:

2*1的小矩形的总个数n

返回值描述:

覆盖一个2*n的大矩形总共有多少种不同的方法(从同一个方向看)

示例1

输入: 0

返回值:0

示例2

输入:1

返回值:1

示例3

输入:4

返回值:5

分析:

首先如果n=0,则只有0种;

如果n=1,也只有1种;

如果n=2,有横竖2种情况:
在这里插入图片描述
如果n=3,有3种情况:
在这里插入图片描述
而如果n=4,有5种情况:
在这里插入图片描述
由规律发现,2 ∗ n 的矩形的情况数为 f(n) = f(n−1) + f(n−2) ,即这就是一个斐波那契数列,按照斐波那契数列的解法来即可,需要注意不同点在于 n 小于等于 2 时,都只有 n 种。

方法一:递归

代码:

class Solution {
public:
    int rectCover(int number) {
        if(number <= 2) //约定 n == 0 时,输出 0, 1时也只有一种
            return number;
        return rectCover(number - 1) + rectCover(number - 2);//f(n-1)+f(n-2)
    }
};

运行时间:110ms
超过28.13% 用C++提交的代码
占用内存:528KB
超过30.69%用C++提交的代码
复杂度分析:
时间复杂度:O(n2) ,树型递归,T(n) = T(n−1) +T(n−2)
空间复杂度:O(n),递归栈深度为树最深处,

方法二:动态规划

具体做法:

对于斐波那契数列的递推公式:f(n) = f(n−1) + f(n−2) ,我们可以用 dp 数组动态规划不断相加得到。

class Solution {
public:
    int rectCover(int number) {
        if(number <= 2) //约定 n == 0 时,输出 0, 1时也只有一种
            return number;
        vector<int> dp(number + 1);
        dp[1] = 1;
        dp[2] = 2;
        for(int i = 3; i <= number; i++)
            dp[i] = dp[i - 1] + dp[i - 2]; //公式不断相加
        return dp[number];
    }
};

但是这个方法使用了 dp 数组,空间复杂度为 O(n),不满足要求,因此我们对空间优化一下:注意到每次循环只使用到了第 i−1 个变量和第 i−2 个变量,那我们可以用两个变量不断滚动来优化。

class Solution {
public:
    int rectCover(int number) {
        if(number <= 2) //约定 n == 0 时,输出 0, 1时也只有一种
            return number;
        int dpi_2 = 1; //初始化n=1
        int dpi_1 = 2; //初始化n=2
        int res = 0;
        for(int i = 3; i <= number; i++){
            res = dpi_1 + dpi_2; //公式相加
            dpi_2 = dpi_1; //变量更新
            dpi_1 = res;
        }
        return res;
    }
};

运行时间:7ms
超过30.44% 用C++提交的代码
占用内存:548KB
超过29.40%用C++提交的代码
复杂度分析:
时间复杂度: O(n),一次遍历
空间复杂度: O(1),常数级遍历

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千北@

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值