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(n−1)F(n−2)⎠⎞=(F(n)+F(n−1)+F(n−2)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)n⎝⎛F(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(i−1)f(i−2)f(i−3)⎠⎞
而我们要求出的向量是:( f ( i ) f ( i − 1 ) f ( i − 2 ) ) \begin{pmatrix} f(i) \\ f(i-1) \\ f(i-2) \end{pmatrix} ⎝⎛f(i)f(i−1)f(i−2)⎠⎞
利用题目中的依赖关系,对目标矩阵元素进行展开:( 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(i−1)f(i−2)⎠⎞=⎝⎛f(i−1)∗1f(i−1)∗1f(i−1)∗0f(i−2)∗1f(i−2)∗0f(i−2)∗1f(i−3)∗1f(i−3)∗1f(i−3)∗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(n−1)f(n−2)⎠⎞=Matn−2∗⎝⎛f(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)