问题:
Fibonacci序列中的每个新术语都是通过添加 前两个任期。
从1和2开始,前10个术语将 是:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
考虑Fibonacci序列中的值,而不是 超过四百万,找到偶数值的总和。
我的代码:(工作正常)
public static void main(String[] agrs){
int prevFirst=0;
int prevSecond=1;
int bound=4_000_000;
int evenSum=0;
boolean exceed=false; //when fib numbers > bound
while(!exceed){
int newFib=prevFirst + prevSecond;
prevFirst = prevSecond;
prevSecond = newFib;
if(newFib > bound){
exceed=true;
break;
}
if(newFib % 2 == 0){
evenSum += newFib;
}
}
System.out.println(evenSum);
}
我正在寻找一种更有效的算法来解决这个问题。任何提示?
答案 0 :(得分:13)
考虑以下规则时:
甚至+偶数=偶数
偶数+奇数=奇数
奇数+偶数=奇数
奇数+奇数=偶数
第一个斐波纳契数的奇偶性是:
o o o o o o e ... ...
因此,基本上,你只需要做三步即可。这是:
(1,1,2)
(3,5,8)
(13,21,34)
鉴于(a,b,c)
,这是(b+c,b+2*c,2*b+3*c)
。
这意味着我们只需要存储最后两个数字,并计算给定的(a,b)
,(a+2*b,2*a+3*b)
。
因此(1,2) -> (5,8) -> (21,34) -> ...
并始终返回最后一个。
这比“过滤器” - 方法更快,因为它使用了减少流水线操作的if语句。
结果代码是:
int b = 1;
int c = 2, d;
long sum = 0;
while(c < 4000000) {
sum += c;
d = b+(c<<0x01);
c = d+b+c;
b = d;
}
System.out.println(sum);
或jdoodle(基准测试,冷启动需要5微秒,平均50纳秒,基于1M次的平均值)。当然,循环中的指令数量更大。但循环重复了三分之一。
答案 1 :(得分:3)
你无法改善它,你所做的任何改进都可以忽略不计,并且依赖于你正在运行的操作系统。
示例:强>
在我的Mac上循环运行代码 1M次 73-75ms(运行几次)。
改变条件:
if(newFib % 2 == 0){
为:
if((newFib & 1) == 0){
再次运行几次我得到了51-54ms。
答案 2 :(得分:3)
假设连续的斐波纳契数
a, b,
c = a + b,
d = a + 2b,
e = 2a + 3b,
f = 3a + 5b,
g = 5a + 8b = a + 4(a + 2b) = a + 4d,
使用
它似乎更有效
ef 0 = 0,ef 1 = 2,ef n = ef n-2 + 4 ef N-1 子>
答案 3 :(得分:1)
因此单次通过时间[ns]为:
最后一个明显胜过我的机器(虽然我希望第一个会是最好的)
没有线程的应用程序32位编译器BDS2006 Trubo C ++
1,2在答案中已经很好地提到了,所以我只评论3:
s+=a&(-((a^1)&1));
(a ^ 1)否定最爱情
好的,这里是代码(如果你想自己编码,请不要进一步阅读):
//---------------------------------------------------------------------------
int euler002()
{
// Each new term in the Fibonacci sequence is generated by adding the previous two terms.
// By starting with 1 and 2, the first 10 terms will be: 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...
// By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
int a,a0=0,a1=1,s=0,N=4000000;
/*
//1. [176 ns]
a=a0+a1; a0=a1; a1=a; // odd
a=a0+a1; a0=a1; a1=a; // even
for (;a<N;)
{
s+=a;
a=a0+a1; a0=a1; a1=a; // odd
a=a0+a1; a0=a1; a1=a; // odd
a=a0+a1; a0=a1; a1=a; // even
}
//2. [179 ns]
for (;;)
{
a=a0+a1; a0=a1; a1=a;
if (a>=N) break;
if ((a&1)==0) s+=a;
}
//3. [169 ns]
for (;;)
{
a=a0+a1; a0=a1; a1=a;
if (a>=N) break;
s+=a&(-((a^1)&1));
}
//4. [105 ns] // [edit1]
a0+=a1; a1+=a0; a=a1; // 2x
for (;a<N;)
{
s+=a; a0+=a1; a1+=a0; // 2x
a=a0+a1; a0=a1; a1=a; // 1x
}
*/
//5. [76 ns] //[ edit2]
a0+=a1; a1+=a0; // 2x
for (;a1<N;)
{
s+=a1; a0+=a1; a1+=a0; // 2x
a=a0; a0=a1; a1+=a; // 1x
}
return s;
}
//---------------------------------------------------------------------------
[edit1]加快代码添加
[edit2]更快的代码添加 - 只需重新排序一些变量和操作使用以获得更快的速度 - [76 ns]减少了操作数,降低了开销和堆垃圾
答案 4 :(得分:1)
如果你查看Fibonacci系列,对于偶数2 8 34 144 610,你会发现偶数之间存在奇妙的关系,例如:
34 = 4*8 + 2,
144 = 34*4 + 8,
610 = 144*4 + 34;
这意味着即使在Fibonacci中,下一个也可以表示如下
Even(n)=4*Even(n-1)+E(n-2);
Java中的
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int t = in.nextInt();
for(int a0 = 0; a0 < t; a0++){
long n = in.nextLong();
long a=2;
long b=8;
long c=0;
long sum=10;
while(b<n)
{
sum +=c;
c=b*4+a;
a=b;
b=c;
}
System.out.println(sum);
}
}
答案 5 :(得分:0)
项目Euler问题2的答案是(在Java中):
int x = 0;
int y = 1;
int z = x + y;
int sumeven = 0;
while(z < 4000000){
x = y;
y = z;
z = x + y;
if(z % 2 == 0){
sumeven += z; /// OR sumeven = sumeven + z
}
}
System.out.printf("sum of the even-valued terms: %d \n", sumeven);
这是最简单的答案。
答案 6 :(得分:0)
F(n)是第n个Fibonnaci数,即F(n)= F(n-1)+ F(n-2)
让我们说F(n)是偶数,然后是
F(n)= F(n-1)+ F(n-2)= F(n-2)+ F(n-3)+ F(n-2)
F(n)= 2F(n-2)+ F(n-3)
- 这证明了每三个项都是偶数(如果F(n-3)是偶数,那么F(n)必须是偶数)
F(n)= 2 [F(n-3)+ F(n-4)] + F(n-3)
= 3F(n-3)+ 2F(n-4)
= 3F(n-3)+ 2F(n-5)+ 2F(n-6)
从等式1:
F(n-3)= 2F(n-5)+ F(n-6)
2F(n-5)= F(n-3)-F(n-6)
F(n)= 3F(n-3)+ [F(n-3)-F(n-6)] + 2F(n-6)
= 4F(n-3)+ F(n-6)
如果偶数序列由每三个数字(n,n-3,n-6,...)组成
甚至Fibonacci序列:
public static long findEvenFibSum(long n){
long term1=0;
long term2=2;
long curr=0;
long sum=term1+term2;
while((curr=(4*term2+term1))<=n){
sum+=curr;
term1=term2;
term2=curr;
}
return sum;
}