如何更快地生成斐波那契数
我是一名 CSE 学生,正在为编程竞赛做准备。现在我正在研究斐波那契数列。我有一个大小约为几千字节的输入文件,其中包含正整数。输入格式看起来像
3 5 6 7 8 0
一个零意味着文件结束。输出应该像
2
5
8
13
21
我的代码
#include<stdio.h>
int fibonacci(int n) {
if (n==1 || n==2)
return 1;
else
return fibonacci(n-1) +fibonacci(n-2);
}
int main() {
int z;
FILE * fp;
fp = fopen ("input.txt","r");
while(fscanf(fp,"%d", &z) && z)
printf("%d \n",fibonacci(z));
return 0;
}
一样该代码适用于示例输入并提供准确的结果,但问题是对于我的真实输入集,它花费的时间比我的时间限制更多。谁能帮我一下。
I am a CSE student and preparing myself for programming contest.Now I am working on Fibonacci series. I have a input file of size about some Kilo bytes containing positive integers. Input formate looks like
3 5 6 7 8 0
A zero means the end of file. Output should like
2
5
8
13
21
my code is
#include<stdio.h>
int fibonacci(int n) {
if (n==1 || n==2)
return 1;
else
return fibonacci(n-1) +fibonacci(n-2);
}
int main() {
int z;
FILE * fp;
fp = fopen ("input.txt","r");
while(fscanf(fp,"%d", &z) && z)
printf("%d \n",fibonacci(z));
return 0;
}
The code works fine for sample input and provide accurate result but problem is for my real input set it is taking more time than my time limit. Can anyone help me out.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(22)
如果内存有限,您可以简单地使用函数的尾递归版本,该函数返回最后两个斐波那契数。
这是
O(n)
并且需要一个常量空间。You could simply use a tail recursion version of a function that returns the two last fibonacci numbers if you have a limit on the memory.
This is
O(n)
and needs a constant space.您可能应该研究一下记忆。
http://en.wikipedia.org/wiki/Memoization
它有一个解释和一个谎言示例就在那里
You should probably look into memoization.
http://en.wikipedia.org/wiki/Memoization
It has an explanation and a fib example right there
您可以通过矩阵乘法来完成此操作,将矩阵求 n 次方,然后乘以一个向量。您可以在对数时间内将其提高功率。
我认为您可以在此处找到问题。它是罗马尼亚语,但您可以使用谷歌翻译进行翻译。这正是您想要的,并且解决方案已列在此处。
You can do this by matrix multiplictation, raising the matrix to power n and then multiply it by an vector. You can raise it to power in logaritmic time.
I think you can find the problem here. It's in romanian but you can translate it with google translate. It's exactly what you want, and the solution it's listed there.
您的算法是递归的,并且大约具有 O(2^N) 复杂度。
这个问题之前在stackoverflow上讨论过:
斐波那契数列的计算复杂性
在该特定讨论中还发布了更快的实现。
Your algorithm is recursive, and approximately has O(2^N) complexity.
This issue has been discussed on stackoverflow before:
Computational complexity of Fibonacci Sequence
There is also a faster implementation posted in that particular discussion.
看看维基百科,有一个公式给出了斐波那契数列中的数字,没有递归全部
Look in Wikipedia, there is a formula that gives the number in the Fibonacci sequence with no recursion at all
使用记忆。也就是说,您缓存答案以避免不必要的递归调用。
这是一个代码示例:
Use memoization. That is, you cache the answers to avoid unnecessary recursive calls.
Here's a code example:
没有人提到 2 值堆栈数组版本,所以我只是为了完整性而这样做。
这是一个 O(n) 常量堆栈空间解决方案,在优化编译时其执行效果与记忆化略有相同。
这里使用的 BM_memoization 只会初始化数组一次,并在每次其他调用中重用它。
优化后,2 值堆栈数组版本的性能与带有临时变量的版本相同。
Nobody mentioned the 2 value stack array version, so I'll just do it for completeness.
This is a O(n) constant stack space solution that will perform slightly the same than memoization when compiled with optimization.
The BM_memoization used here will initialize the array only once and reuse it for every other call.
The 2 value stack array version performs identically as a version with a temporary variable when optimized.
您还可以使用生成斐波那契数列的快速倍增方法
链接: fastest-way-to-compute -fibonacci-number
它实际上是由矩阵求幂方法的结果推导出来的。
You can also use the fast doubling method of generating Fibonacci series
Link: fastest-way-to-compute-fibonacci-number
It is actually derived from the results of the matrix exponentiation method.
使用黄金比例
Use the golden-ratio
构建一个数组 Answer[100],在其中缓存 fibonacci(n) 的结果。
检查您的斐波那契代码,看看您是否已预先计算出答案,并且
使用该结果。结果会让你大吃一惊。
Build an array Answer[100] in which you cache the results of fibonacci(n).
Check in your fibonacci code to see if you have precomputed the answer, and
use that result. The results will astonish you.
您是否保证,如您的示例所示,输入将按升序提供给您?如果是这样,你甚至不需要记忆;只需跟踪最后两个结果,开始生成序列,但如果 N 是输入中的下一个索引,则仅显示序列中的第 N 个数字。当你达到索引 0 时停止。
类似这样的事情:
我留下退出条件并实际为你生成序列。
Are you guaranteed that, as in your example, the input will be given to you in ascending order? If so, you don't even need memoization; just keep track of the last two results, start generating the sequence but only display the Nth number in the sequence if N is the next index in your input. Stop when you hit index 0.
Something like this:
I leave exit conditions and actually generating the sequence to you.
在 C# 中:
In C#:
矩阵乘法,无浮点运算,O(log N) 时间复杂度(假设整数乘法/加法在恒定时间内完成)。
这是Python代码
Matrix multiplication, no float arithmetic, O(log N) time complexity assuming integer multiplication/addition is done in constant time.
Here goes python code
您可以减少 if 语句的开销: Calculate Fibonacci Numbers Recursively in C
You can reduce the overhead of the if statement: Calculating Fibonacci Numbers Recursively in C
首先,您可以使用 memoization 或同一算法的迭代实现。
考虑您的算法进行的递归调用次数:
fibonacci(n) 调用 fibonacci(n-1) 和 fibonacci(n-2)
fibonacci(n-1) 调用 fibonacci(n-2) 和
fibonacci(n-3)
fibonacci(n-2) 调用
fibonacci(n-3)
和 fibonacci(n-4)注意到一个模式了吗?您计算同一函数的次数超出了需要的次数。
迭代实现将使用数组:
这已经比您的方法快得多。您可以按照相同的原则更快地完成此操作,只需构建一次数组,直到达到 n 的最大值,然后通过打印数组的元素在单个操作中打印正确的数字。这样您就不必为每个查询调用该函数。
如果您无法承担初始预计算时间(但这通常仅在您被要求对结果取模时才会发生,否则他们可能不希望您实现大数算术,而预计算是最好的解决方案),请阅读斐波那契维基页面了解其他方法。重点关注矩阵方法,在竞赛中了解该方法非常有用。
First of all, you can use memoization or an iterative implementation of the same algorithm.
Consider the number of recursive calls your algorithm makes:
fibonacci(n) calls fibonacci(n-1) and fibonacci(n-2)
fibonacci(n-1) calls fibonacci(n-2) and
fibonacci(n-3)
fibonacci(n-2) calls
fibonacci(n-3)
and fibonacci(n-4)Notice a pattern? You are computing the same function a lot more times than needed.
An iterative implementation would use an array:
This is already much faster than your approach. You can do it faster on the same principle by only building the array once up until the maximum value of
n
, then just print the correct number in a single operation by printing an element of your array. This way you don't call the function for every query.If you can't afford the initial precomputation time (but this usually only happens if you're asked for the result modulo something, otherwise they probably don't expect you to implement big number arithmetic and precomputation is the best solution), read the fibonacci wiki page for other methods. Focus on the matrix approach, that one is very good to know in a contest.
在函数式编程中,有一种特殊的斐波那契计数算法。该算法使用累积递归。累积递归用于最小化算法使用的堆栈大小。我认为这会帮助你最大限度地减少时间。如果你愿意的话可以尝试一下。
In the functional programming there is a special algorithm for counting fibonacci. The algorithm uses accumulative recursion. Accumulative recursion are used to minimize the stack size used by algorithms. I think it will help you to minimize the time. You can try it if you want.
使用以下任意一种:两个递归示例,一个使用 for 循环 O(n) 时间,一个使用黄金比例 O(1) 时间:
use any of these: Two Examples of recursion, One with for Loop O(n) time and one with golden ratio O(1) time:
这与之前给出的答案类似,但有一些修改。正如其他答案中所述,记忆是实现此目的的另一种方法,但我不喜欢随着技术变化而无法扩展的代码(
unsigned int
的大小因平台而异),因此最高值可以达到的顺序也可能会有所不同,而且在我看来,记忆是丑陋的。此外,如果您使用
,则可以编写一个编译时常量表达式,该表达式将为您提供序列中任何整数数据类型均可达到的最大索引。This is similar to answers given before, but with some modifications. Memorization, as stated in other answers, is another way to do this, but I dislike code that doesn't scale as technology changes (size of an
unsigned int
varies depending on the platform) so the highest value in the sequence that can be reached may also vary, and memorization is ugly in my opinion.Additionally, if you use
<limits>
its possible to write a compile-time constant expression that would give you the largest index within the sequence that can be reached for any integral data type.