当k = 2时,我们都知道斐波纳契系列。
即:1,1,2,3,5,8,13
但这是2-fibonacci。像这样,我可以计算第三个斐波那契:
1,1,2,4,7,13,24
4-fibonacci:
1,1,2,4,8,15,29
......等等
我要问的是计算k-fibonacci系列中'n'元素的算法。
像这样:如果我要求fibonacci(n=5,k=4)
,结果应该是:8
,即4-fibonacci系列中的第五个元素。
我没有在任何网站上找到它。帮助的资源可以是mathworld
任何?如果你知道python,我更喜欢。但如果没有,任何语言或算法都可以提供帮助。
提示我认为这有助于: 让我们分析k-fibonacci系列,其中k将从1到5
k fibonacci series
1 1, 1, 1, 1, 1, 1, 1, 1,1, 1, 1, ...
2 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...
3 1, 1, 2, 4, 7, 13, 24, 44, 81, ...
4 1, 1, 2, 4, 8, 15, 29, 56, 108, ...
5 1, 1, 2, 4, 8, 16, 31, 61, 120, ...
分析这个,我们可以看到k-fibonacci系列上的数组[0:k]等于 以前的斐波那契系列,它一直持续到k = 1
即。 (我会试着表明,但我找不到正确的说法):
k fibonacci series
1 1,
2 1, 1,
3 1, 1, 2,
4 1, 1, 2, 4,
5 1, 1, 2, 4, 8,
希望我能以某种方式解决这个问题。
[python中的解决方案(如果有人需要)]
class Fibonacci:
def __init__(self, k):
self.cache = []
self.k = k
#Bootstrap the cache
self.cache.append(1)
for i in range(1,k+1):
self.cache.append(1 << (i-1))
def fib(self, n):
#Extend cache until it includes value for n.
#(If we've already computed a value for n, we won't loop at all.)
for i in range(len(self.cache), n+1):
self.cache.append(2 * self.cache[i-1] - self.cache[i-self.k-1])
return self.cache[n]
#example for k = 5
if __name__ == '__main__':
k = 5
f = Fibonacci(k)
for i in range(10):
print f.fib(i),
答案 0 :(得分:9)
与2-fibonacci一样,动态编程是最佳选择。在k
时间内记住早期O(n)
的值以快速计算后面的值。
您可以用来提高k
大值的速度的另一个优化是将f(n-k)
添加到f(n-1)
以获取f(n)
,而只是使用(2*f(n-1)) - f(n-k-1)
}。由于这仅使用2次查找,2次添加和乘法,因此k
查找和k
在k
变大时会增加(但它仍然是O(n)
,一个较小的常数乘数)。
答案 1 :(得分:7)
这是一个基于Ambers answer的迭代解决方案:
class Fibonacci {
List<Integer> cache = new ArrayList<Integer>();
final int K;
public Fibonacci(int k) {
this.K = k;
// Bootstrap the cache
cache.add(1);
for (int i = 1; i <= k; i++)
cache.add(1 << (i-1));
}
public long fib(int n) {
// Extend cache until it includes value for n.
// (If we've already computed a value for n, we won't loop at all.)
for (int i = cache.size(); i <= n; i++)
cache.add(2 * cache.get(i-1) - cache.get(i-K-1));
// Return cached value.
return cache.get(n);
}
}
测试如下:
public class Main {
public static void main(String[] args) {
System.out.println("k fibonacci series");
for (int k = 1; k <= 5; k++) {
System.out.print(k + " ");
Fibonacci f = new Fibonacci(k);
for (int i = 0; i < 10; i++)
System.out.print(f.fib(i) + ", ");
System.out.println("...");
}
}
}
并打印
k fibonacci series
1 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, ...
2 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...
3 1, 1, 2, 4, 7, 13, 24, 44, 81, 149, ...
4 1, 1, 2, 4, 8, 15, 29, 56, 108, 208, ...
5 1, 1, 2, 4, 8, 16, 31, 61, 120, 236, ...
答案 2 :(得分:7)
如果您只想解决一个值(即fibonnaci(n,k)
),那么更有效的方法是使用线性递归,它将是O(k^3 log(n))
(k^3
因子可以用更好的矩阵乘法算法进行改进。)
基本上,这种方法的工作方式是将向量F(n), F(n-1) ... F(n-k)
表示为向量F(n-1), F(n-2) ... F(n-k-1)
的矩阵时间。然后,由于矩阵乘法是关联的,您可以将矩阵提升为幂,并将其乘以初始向量F(k), F(k-1) ... F(0)
。
可以在O(log(n))
中使用指数通过平方来进行指数化。
例如,对于k = 3的情况,我们将:
[F(n+2)] [1 1 1] [F(n+1)]
[F(n+1)] = [1 0 0] [F(n) ]
[F(n) ] [0 1 0] [F(n-1)]
所以要解决F(n),你只需找到
[F(n+2)] [1 1 1]^n [F(2)]
[F(n+1)] = [1 0 0] [F(1)]
[F(n) ] [0 1 0] [F(0)]
答案 3 :(得分:3)
直接的方法是简单地将最后的k个术语相加以每次获得当前术语。这给了我们一个O(n * k)运行时。
另一种方法是使用矩阵求幂。对于k = 2,您可以使用矩阵对情况进行建模。从(Fn-1,Fn-2)我们可以通过计算(Fn-1 + Fn-2,Fn-1)导出(Fn,Fn-1)。
因此,乘以coloumn矩阵
[
Fn-1
Fn-2
]
使用方阵
[
1 1
1 0
]
产量
[
Fn-1 + Fn-2
Fn-1
]
从而为我们提供了Fn的价值。
当然,这还不比O(n * k)好。我们仍然会运行O(n)循环/递归来获得第n个项。
观察 (为方便起见,我现在正在横向编写coloumn矢量,但它们仍然是coloumns)
[[Fn],[Fn-1]] = [[Fn-1],[Fn-2]]*[[1,1] [1,0]]
= [[Fn-2],[Fn-3]]*[[1,1] [1,0]]*[[1,1] [1,0]]
= [[Fn-3],[Fn-4]]*[[1,1] [1,0]]*[[1,1] [1,0]]*[[1,1] [1,0]]
= [[Fn-3],[Fn-4]]*([[1,1] [1,0]])^3
= [[Fn-k],[Fn-k-1]]*([[1,1] [1,0]])^k
= [[F1],[F0]]*([[1,1] [1,0]])^n-1
现在,([[1,1] [1,0]])^n-1
可以使用exponentiation by squaring在O(log(n))时间内计算。因此,您可以使用最多log(n)矩阵乘法计算k-fibonacci的第n项。使用直接的矩阵乘法,这给了我们O(k ^ 3 * log(n))的复杂性。
编辑:
以下是Python中的一些代码我一起入侵以说明我说的更好:
from itertools import izip
def expo(matrix,power, identity):
if power==0:
return identity
elif power==1:
return matrix
elif power&1:
return multiply(matrix,expo(matrix,power-1,identity))
else:
x=expo(matrix,power>>1,identity)
return multiply(x,x)
def multiply(A,B):
ret=[list() for i in xrange(len(B))]
for i,row in enumerate(B):
for j in xrange(len(A[0])):
coloumn=(r[j] for r in A)
ret[i].append(vector_multiply(row,coloumn))
return ret
def vector_multiply(X,Y):
return sum(a*b for (a,b) in izip(X,Y))
def fibonacci(n,start=[[1],[0]], k=2):
identity=[[1 if col==row else 0 for col in xrange(k)] for row in xrange(k)] # identity matrix
# build the matrix for k
matrix=[[1]*k]
for i in xrange(1,k):
matrix.append([0]*(i-1)+[1]+[0]*(k-i))
return multiply(start,expo(matrix,n-1,identity))[0][0]
print fibonacci(10)
答案 4 :(得分:1)
为了练习它,我在Haskell中实现了它。以下是fib
通常作为列表理解编写的方式:
fib = 1:1:[x + y | (x,y) <- zip fib $ tail fib]
推广到'k'术语很困难,因为zip
需要两个参数。有一个zip3
,zip4
等,但没有一般zipn
。但是,我们可以废除创建对的技术,而是生成“序列的所有尾部”,并对这些成员的第一个k
成员求和。以下是查找k = 2情况的方法:
fib2 = 1:1:[sum $ take 2 x | x <- tails fib2]
推广到任何k
:
fibk k = fibk'
where fibk' = take (k - 1) (repeat 0) ++ (1:[sum $ take k x | x <- tails fibk'])
> take 10 $ fibk 2
[0,1,1,2,3,5,8,13,21,34]
> take 10 $ fibk 3
[0,0,1,1,2,4,7,13,24,44]
> take 10 $ fibk 4
[0,0,0,1,1,2,4,8,15,29]
答案 5 :(得分:1)
下面的另一个log(n)解决方案
Source and explanation here。
如果进行了大量调用,您可以缓存解决方案。
public class Main {
/*
* F(2n) = F(n) * (2*F(n+1) - F(n))
* F(2n+1) = F(n+1)^2 + F(n)^2
* Compute up to n = 92, due to long limitation<br>
* Use different type for larger numbers
*/
public static long getNthFibonacci(int n) {
long a = 0;
long b = 1;
for (int i = 31 - Integer.numberOfLeadingZeros(n); i >= 0; i--) {
long d = a * ((b << 1) - a); // F(2n)
long e = a * a + b * b; // F(2n+1)
a = d;
b = e;
if (((1 << i) & n) != 0) { // advance by one
long c = a + b;
a = b;
b = c;
}
}
return a;
}
}
答案 6 :(得分:1)
人们已经提到了O(logN)解决方案。没有多少人理解矩阵中被取幂的常数是如何形成的。如果您想详细分析如何使用矩阵来解决线性递归问题,请查看Code Overflow.
答案 7 :(得分:0)
我想你需要的东西比O(nk)
更好
对于O(nk)
,你可以天真地计算它
如果您有n <= N
和k <= K
的上限,您还可以构建一次矩阵NxK
,并在需要该值时随时查询它。
修改强>
如果您想进一步深入学习数学,可以尝试阅读this paper on Generalized Order-k Pell Numbers。
答案 8 :(得分:0)
简单的强力解决方案
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int k = scanner.nextInt();
long formula ;
formula = k ;
long[] fib = new long[n+1];
for (int i = 1; i <=n ; i++) {
if(i<=k) fib[i] = 1;
else {
fib[i] = formula;
formula =(formula*2-fib[i-k]);
}
}
for (int i = 1; i <=fib.length-1 ; i++) {
System.out.print(fib[i]+" ");
}
答案 9 :(得分:0)
这是一个高效,简洁,精确的封闭式解决方案。
A
这是输出:
X
该方法有效地计算多项式环Z [X] /(X ^ kX ^(k-1)-X ^(k-2)-...- 1)中的X ^(n + k)(其中最终多项式中常量项的结果有点令人惊讶的是fibk(n,k)),但使用足够大的整数(function () {
var app = angular.module('myApp', []);
app.controller('TabController', function () {
if(typeof(localStorage.currentTab)=="undefined")
this.tab = 1;
else
this.tab = parseInt(localStorage.currentTab);
this.setTab = function (tabId) {
localStorage.currentTab=tabId;
this.tab = tabId;
};
this.isSet = function (tabId) {
return this.tab === tabId;
};
});
})();
代替# This works, but it is not optimal, could crash
queue_listen_name = config["database"]["listen_channel"]
cur.execute("LISTEN %s;" % ext.quote_ident(queue_listen_name))
来执行整数计算。