10 斐波那契数列+ 矩形覆盖+跳台阶

10.1 斐波那契数列

题目描述

求斐波那契数列的第 n 项,n <= 39。
在这里插入图片描述

解题思路

1.递归

下面的递归方法复杂度太高,无法通过;

class Solution {
public:
    int Fibonacci(int n) {
        if(n < 0)
            return 0;
        if(n == 0 || n == 1)
            return n;
        return Fibonacci(n-1) + Fibonacci(n-2);

    }
};

2. 动态规划

如果使用递归求解,会重复计算一些子问题。例如,计算 f(4) 需要计算 f(3) 和 f(2),计算 f(3) 需要计算 f(2) 和 f(1),可以看到 f(2) 被重复计算了。
递归是将一个问题划分成多个子问题求解,动态规划也是如此,但是动态规划会把子问题的解缓存起来,从而避免重复求解子问题。
此时的复杂度为o(N)

class Solution {
public:
    int Fibonacci(int n) {
        vector<int> tmp;
        tmp.reserve(n+1);  //此处必须声明容器的大小,不然下面会出现内存非法访问
        tmp.push_back(0);
        tmp.push_back(1);
        for(int i = 2; i <= n; i++)
        {
            tmp[i] = tmp[i-1] + tmp[i-2];
        }
        return tmp[n];

    }
};

关于声明固定长度的数组:

//use vector
vector<int> tmp;
tmp.reserve(n+1);

//use array
int* tmp = new int[n+1];

3.动态规划的改进

考虑到第 i 项只与第 i-1 和第 i-2 项有关,因此只需要存储前两项的值就能求解第 i 项,从而将空间复杂度由 O(N) 降低为 O(1)。

class Solution {
public:
    int Fibonacci(int n) {
        if(n <= 1)
            return n;
        int pre0 = 0, pre1 = 1;
        int ret = 0;
        for(int i = 2; i <= n; i++)
        {
            ret = pre0 + pre1;
            pre0 = pre1;
            pre1 = ret;
        }
        return ret;
            

    }
};

此外,由于待求解的 n 小于 40,因此可以将前 40 项的结果先进行计算,之后就能以 O(1) 时间复杂度得到第 n 项的值。

10.2 矩形覆盖

题目

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

解题思路

当 n 为 1 时,只有一种覆盖方法;
当 n 为 2 时,有两种覆盖方法;
要覆盖 2n 的大矩形,可以先覆盖 21 的矩形,再覆盖 2*(n-1) 的矩形;或者先覆盖 22 的矩形,再覆盖 2(n-2) 的矩形。而覆盖 2*(n-1) 和 2*(n-2) 的矩形可以看成子问题。该问题的递推公式如下:
在这里插入图片描述

class Solution {
public:
    int rectCover(int number) {
        if(number <= 2)
            return number;
        int pre1 = 1, pre2 = 2;
        int ret = 0;
        for(int i = 3; i <= number; i++)
        {
            ret = pre1 + pre2;
            pre1 = pre2;
            pre2 = ret;
        }
        return ret;

    }
};

10.3 跳台阶

题目

一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

解题思路

当 n = 1 时,只有一种跳法;
当 n = 2 时,有两种跳法;
跳 n 阶台阶,可以先跳 1 阶台阶,再跳 n-1 阶台阶;或者先跳 2 阶台阶,再跳 n-2 阶台阶。而 n-1 和 n-2 阶台阶的跳法可以看成子问题,该问题的递推公式为:
在这里插入图片描述
代码段

class Solution {
public:
    int jumpFloor(int n) {
        if (n <= 2)
        return n;
        int pre2 = 1, pre1 = 2;
        int result = 1;
        for (int i = 2; i < n; i++) // i是取值到n-1
        {
            result = pre2 + pre1;
            pre2 = pre1;
            pre1 = result;
        }
        return result;
    }
};

10.4 变态跳台阶

题目描述

一只青蛙一次可以跳上 1 级台阶,也可以跳上 2 级… 它也可以跳上 n 级。求该青蛙跳上一个 n 级的台阶总共有多少种跳法。

解题思路

动态规划

class Solution {
public:
    int jumpFloorII(int number) {
        int* array = new int[number];
        for(int i = 0; i < number; i++)
        {
            array[i] = 1;
        }
        //array.fill(1);
        for(int i = 0; i < number; i++)
        {
            for(int j = 0; j <i; j++)
            {
                array[i] += array[j];
            }
        }
        return array[number-1];

    }
};

数学推导

跳上 n-1 级台阶,可以从 n-2 级跳 1 级上去,也可以从 n-3 级跳 2 级上去…,那么:
f(n-1) = f(n-2) + f(n-3) + … + f(0)
同样,跳上 n 级台阶,可以从 n-1 级跳 1 级上去,也可以从 n-2 级跳 2 级上去… ,那么:
f(n) = f(n-1) + f(n-2) + … + f(0)
综上:
f(n) - f(n-1) = f(n-1)
即:
f(n) = 2*f(n-1)

补充:
c++中:
pow() 函数用来求 x 的 y 次幂(次方),其原型为:
double pow(double x, double y);

class Solution {
public:
    int jumpFloorII(int number) {
        return (int) pow(2, number - 1);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值