我想以对数时间计算第n个斐波纳西数。所以,我写了这个函数
vector<vector<ll> > expon(ll k)
{
if(k==1)
{
vector<vector<ll>> A({{1,1},{1,0}});
return A;
}
auto A = expon(k/2);
ll tmp[2][2] = {{0,0},{0,0}};
for(int i=0;i<2;++i)
for(int j=0;j<2;++j)
for(int k=0;k<2;++k)
tmp[i][j] += (A[i][k]*A[k][j])%modv;
vector<vector<ll>> B({{tmp[0][0],tmp[0][1]},{tmp[1][0],tmp[1][1]}});
if(k%2)
return vector<vector<ll>>({{(tmp[0][0]+tmp[0][1])%modv,tmp[0][0]},{(tmp[1][0]+tmp[1][1])%modv,tmp[1][0]}});
else
return B;
}
但有些我觉得它花了太多时间。所以我想知道,它实际上是对数吗?我的意思是我的代码。
答案 0 :(得分:2)
复杂性是对数的,但实施不是最理想的。您不需要递归,也不需要为矩阵的每个幂创建单独的向量实例。另一个注意事项 - 您有重复的变量k
,这会导致警告,具体取决于编译器设置。
有一种方法可以检查给定的代码段是否为对数 - 衡量输入n
,n^2
,n^4
所需的时间。如果复杂性是对数的,则每个测试应该花费大约两倍的前一个测试(同时请记住,测量可能在小持续时间内不准确)。
答案 1 :(得分:1)
你的算法是 O(k * logn),技术上是 O(logn)但是常量k可能很大,因为你在每次递归时创建向量分配所以它很慢。
尝试使用迭代解决方案: -
mat ans =[1,1,1,1];
while(k>0) {
if(k&1) {
ans = ans*a;
}
k=k>>1;
a = a*a;
}
您可以注意到这是O(logn)
并且不需要重新分配,而是需要两个2X2矩阵。