泰波那契数以及对long/int范围的思考

1137. 第 N 个泰波那契数

递归(超时)

class Solution {
public:
    int tribonacci(int n) {
        switch(n){
            case 0:
                return 0;
            case 1:
                return 1;
            case 2:
                return 1;
            default:
                return tribonacci(n-1)+tribonacci(n-2)+tribonacci(n-3);
        }
    }
};

**时间复杂度:**O(3^n)

**空间复杂度:**O(n)

使用带备忘录的递归

class Solution {
public:
    int arr[38] = {0,1,1};
    int tribonacci(int n) {

        if(n<3){
            return arr[n];
        }

        if(arr[n]){
            return arr[n];
        }else{
            arr[n] = tribonacci(n-1)+tribonacci(n-2)+tribonacci(n-3);
            return arr[n];
        }
    }
  
};

**时间复杂度:**O(n)

**空间复杂度:**O(n)

尾递归

自己写的

class Solution {
public:

    int tribonacci(int n) {
        if(n==0)return 0;
        else if(n<3)return 1;
        else return temp(0,1,1,n);
    }

    int temp(int first,int second,int third,int n){
        int fourth = first+second+third;
         if(n==3)return fourth;
        return temp(second,third,fourth,n-1);
    }
  
};

参考斐波那契数尾递归的写法

class Solution {
public:

    int tribonacci(int n) {
        return temp(0,1,1,n);
    }

    int temp(int first,int second,int third,int n){
        if(n==0)return 0;
        if(n<3)return 1;
        if(n==3)return first+second+third;
        return temp(second,third,first+second+third,n-1);
    }
  
};

**时间复杂度:**O(n)

**空间复杂度:**O(1)

滚动数组

class Solution {
public:

    int tribonacci(int n) {
        int first = 0;
        int second = 1;
        int third = 1;
        if(n==0)return first;
        if(n<3)return third;
        for(int i = 2 ; i < n ; i++){
            int p = first+second+third;
            first = second;
            second = third;
            third = p;
        }
        return third;

    }
};

**时间复杂度:**O(n)

**空间复杂度:**O(1)

矩阵快速幂

尝试复现一下斐波那契数的矩阵快速幂

同样可以发现递推关系
( 1 1 1 1 0 0 ) ( F ( n ) F ( n − 1 ) F ( n − 2 ) ) = ( F ( n ) + F ( n − 1 ) + F ( n − 2 ) F ( n ) ) = ( F ( n + 1 ) F ( n ) ) \begin{pmatrix} 1 & 1 & 1 \\ 1 & 0 & 0 \end{pmatrix} \begin{pmatrix} F(n) \\ F(n-1) \\ F(n-2) \end{pmatrix}= \begin{pmatrix} F(n)+F(n-1)+F(n-2) \\ F(n) \end{pmatrix}= \begin{pmatrix} F(n+1) \\ F(n) \end{pmatrix} (111010)F(n)F(n1)F(n2)=(F(n)+F(n1)+F(n2)F(n))=(F(n+1)F(n))

( F ( n + 1 ) F ( n ) ) = ( 1 1 1 1 0 0 ) n ( F ( 2 ) F ( 1 ) F ( 0 ) ) \begin{pmatrix} F(n+1) \\ F(n) \end{pmatrix}= \begin{pmatrix} 1&1&1 \\ 1&0&0 \end{pmatrix}^n \begin{pmatrix} F(2) \\ F(1) \\ F(0) \end{pmatrix} (F(n+1)F(n))=(111010)nF(2)F(1)F(0)
然后发现这个矩阵的n次幂不会求😓

显然不是这样子的!!

官方不愧是你,看得我一脸闷逼,还是【宫水三叶】讲得好

根据题目的递推关系(i>=3):

f(i) = f(i - 1) + f(i - 2) + f(i - 3)

我们发现要求解 f(i),其依赖的是 f(i - 1)、f(i - 2) 和 f(i - 3)。

存为列向量:
( f ( i − 1 ) f ( i − 2 ) f ( i − 3 ) ) \begin{pmatrix} f(i-1) \\ f(i-2) \\ f(i-3) \end{pmatrix} f(i1)f(i2)f(i3)
而我们要求出的向量是:

( f ( i ) f ( i − 1 ) f ( i − 2 ) ) \begin{pmatrix} f(i) \\ f(i-1) \\ f(i-2) \end{pmatrix} f(i)f(i1)f(i2)
利用题目中的依赖关系,对目标矩阵元素进行展开:

( f ( i ) f ( i − 1 ) f ( i − 2 ) ) = ( f ( i − 1 ) ∗ 1 f ( i − 2 ) ∗ 1 f ( i − 3 ) ∗ 1 f ( i − 1 ) ∗ 1 f ( i − 2 ) ∗ 0 f ( i − 3 ) ∗ 1 f ( i − 1 ) ∗ 0 f ( i − 2 ) ∗ 1 f ( i − 3 ) ∗ 1 ) \begin{pmatrix} f(i) \\ f(i-1) \\ f(i-2) \end{pmatrix}= \begin{pmatrix} f(i-1)*1 &f(i-2)*1 &f(i-3)*1\\ f(i-1)*1 &f(i-2)*0 &f(i-3)*1\\ f(i-1)*0 &f(i-2)*1 &f(i-3)*1\\ \end{pmatrix} f(i)f(i1)f(i2)=f(i1)1f(i1)1f(i1)0f(i2)1f(i2)0f(i2)1f(i3)1f(i3)1f(i3)1
我们令

M a t = ( 1 1 1 1 0 0 0 1 0 ) Mat = \begin{pmatrix} 1&1&1 \\ 1&0&0 \\ 0&1&0 \end{pmatrix} Mat=110101100

( f ( n ) f ( n − 1 ) f ( n − 2 ) ) = M a t n − 2 ∗ ( f ( 2 ) f ( 1 ) f ( 0 ) ) \begin{pmatrix} f(n) \\ f(n-1) \\ f(n-2) \end{pmatrix} = Mat^{n-2}* \begin{pmatrix} f(2) \\ f(1) \\ f(0) \end{pmatrix} f(n)f(n1)f(n2)=Matn2f(2)f(1)f(0)

class Solution {
public:

    int tribonacci(int n) {
        if (n < 2) {
            return n;
        }
        if (n == 2)return 1;
        vector<vector<long>> q{{1, 1, 1}, {1, 0, 0},{0, 1, 0}};
        vector<vector<long>> res = matrix_pow(q, n - 2);
        return res[0][0]+res[0][1];
    }

    vector<vector<long>> matrix_pow(vector<vector<long>>& a, int n) {
        vector<vector<long>> ret{{1, 0, 0}, {0, 1, 0}, {0, 0, 1}};//单位矩阵
        while (n > 0) {
            if (n & 1) {	
                ret = matrix_multiply(ret, a);
            }
            n >>= 1;
            a = matrix_multiply(a, a);
        }
        return ret;
    }

    vector<vector<long>> matrix_multiply(vector<vector<long>>& a,vector<vector<long>>& b) {
        vector<vector<long>> c{{0, 0, 0}, {0, 0, 0},{0, 0, 0}};
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                c[i][j] = a[i][0] * b[0][j] + a[i][1] * b[1][j] + a[i][2] * b[2][j];
            }
        }
        return c;
    }
};

这里用long是由于int会超出限制。如下图:

在这里插入图片描述

我在自己的编译器执行,发现long 的长度为:2147483647,和int一样,转到定义,发现两者表示的是同样的东西

#define int EMIT WARNING C4005 #define long EMIT WARNING C4005

其实这个跟操作系统有关系:

32位系统:long是4字节32位,int是4字节32位。

64位系统:long是8字节64位,int是4字节32位。

于是我一看,哦吼,我的编译器居然默认在Win_32下运行的,但是我把他改为X64时。。。发现并没有啥软用。

查了1个小时,发现一个答案比较合适:https://bbs.csdn.net/topics/350124673

别讨论了,这个问题讨论过很多次了. 编译器拥有最高的决定权.
int 在主流的64位编译器里 的确就是4字节,但也有64位的编译器用的是8字节的int.

有时候大多数编译器会共同遵循某个原则, 结果就被理解成 系统的影响或者标准的规定.

实际上关于这类问题最最根本的标准是这个:
" 你调试出多少,就是多少了.没理由 没原因.大多数编译器喜欢这样. "

然后又翻到如何执行到真正的64位程序

要生成真正的64位程序,请在装好VS2005的64编译器后,  
工程--属性--C++--预处理器--WIN64
工程--属性--链接--目标计算机--X64,

归根到底都是编译器的问题。。。

时间复杂度:O(log n)。

空间复杂度:O(1)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值