flyinghearts《编程之美》读书笔记连载(8)(转)
2010-07-26 13:36
148 查看
原贴地址:http://blog.csdn.net/flyinghearts/archive/2010/05/18/5605933.aspx
2.9 Fibonacci序列
计算Fibonacci序列最直接的方法就是利用递推公式 F(n+2)=F(n+1)+F(n)。而用通项公式来求解是错误的,用浮点数表示无理数本来就有误差,经过n次方后,当n相当大时,误差能足够大到影响浮点数转为整数时的精度,得到的结果根本不准。
用矩阵来计算,虽然时间复杂度降到O(lg n),但要用到矩阵类,相当麻烦。观察:
F(n+2)=F(n)+F(n-1)=2*F(n-1)+F(n-2)=3*F(n-2)+2*F(n-4)
用归纳法很容易证明 F(n) = F(k)*F(n+1-k) + F(k-1)*F(n-k),利用该递推公式和原递推公式,要计算F(n),只要计算F([n/2])和F([n/2]+1),时间复杂度为 O(lg n)。如:要计算F(58), 由 58 -> 29,30 -> 14,15 -> 7,8 -> 3,4 -> 1,2 可知只要算5次。可以用一个栈保存要计算的数,实际上,将n的最高位1(假设在第k位)左边的0去除掉后,第m次要计算的数就是:第k位到第k-m+1位这m个位组成的值为t(m),则第m-1次组成的值为t(m-1),则t(m)=2*t(m-1)+(第k-m+1位是否为1)。若第m-1次计算得到了 f(k)和f(k+1),则第m次计算:
具体公式见下面代码。
下面是计算F(n)最后四位数(某道ACM题)的代码。
view plaincopy to clipboardprint?
/* Fibonacci 数列第N 个数的最后4 位数
注意,当 N>93 时 第N 个数的值超过64 位无符号整数可表示的范围。
F(n+2)=F(n)+F(n-1) F(0)=0 F(1)=1 F(2)=1 ==>
F(n)=F(k)*F(n+1-k) + F(k-1)*F(n-k) ==>
F(2*n)= F(n+1)*F(n)+F(n)*F(n-1)=(F(n+1)+F(n-1))*F(n)= (F(n+1)*2-F(n))*F(n)
F(2*n+1)=F(n+1)*F(n+1)+F(n)*F(n)
F(2*n+2)= F(n+2)*F(n+1)+F(n+1)*F(n)=(F(n+2)+F(n))*F(n+1)= (F(n+1)+F(n)*2)*F(n+1)
*/
unsigned fib_last4 ( unsigned num )
{
if ( num == 0 ) return 0 ;
const unsigned M = 10000 ;
unsigned ret = 1 , next = 1 , ret_ = ret ;
unsigned mask = 1 , tt = num ;
while ( tt >>= 1 ) mask <<= 1 ;
while ( mask >>= 1 ){
if ( num & mask ){
ret_ = ret * ret + next * next ;
next = ( ret + ret + next ) * next ;
} else {
// 多加一个M ,避免 2*next-ret 是负数,造成结果不对
ret_ = ( next + next + M - ret ) * ret ;
next = ret * ret + next * next ;
}
ret = ret_ % M ;
next = next % M ;
}
return ret ;
}
2.9 Fibonacci序列
计算Fibonacci序列最直接的方法就是利用递推公式 F(n+2)=F(n+1)+F(n)。而用通项公式来求解是错误的,用浮点数表示无理数本来就有误差,经过n次方后,当n相当大时,误差能足够大到影响浮点数转为整数时的精度,得到的结果根本不准。
用矩阵来计算,虽然时间复杂度降到O(lg n),但要用到矩阵类,相当麻烦。观察:
F(n+2)=F(n)+F(n-1)=2*F(n-1)+F(n-2)=3*F(n-2)+2*F(n-4)
用归纳法很容易证明 F(n) = F(k)*F(n+1-k) + F(k-1)*F(n-k),利用该递推公式和原递推公式,要计算F(n),只要计算F([n/2])和F([n/2]+1),时间复杂度为 O(lg n)。如:要计算F(58), 由 58 -> 29,30 -> 14,15 -> 7,8 -> 3,4 -> 1,2 可知只要算5次。可以用一个栈保存要计算的数,实际上,将n的最高位1(假设在第k位)左边的0去除掉后,第m次要计算的数就是:第k位到第k-m+1位这m个位组成的值为t(m),则第m-1次组成的值为t(m-1),则t(m)=2*t(m-1)+(第k-m+1位是否为1)。若第m-1次计算得到了 f(k)和f(k+1),则第m次计算:
第k-m+1位 | 已计算 | 待计算 |
1 | f(k) f(k+1) | f(2*k+1),f(2*k+2) |
0 | f(2*k),f(2*k+1) |
下面是计算F(n)最后四位数(某道ACM题)的代码。
view plaincopy to clipboardprint?
/* Fibonacci 数列第N 个数的最后4 位数
注意,当 N>93 时 第N 个数的值超过64 位无符号整数可表示的范围。
F(n+2)=F(n)+F(n-1) F(0)=0 F(1)=1 F(2)=1 ==>
F(n)=F(k)*F(n+1-k) + F(k-1)*F(n-k) ==>
F(2*n)= F(n+1)*F(n)+F(n)*F(n-1)=(F(n+1)+F(n-1))*F(n)= (F(n+1)*2-F(n))*F(n)
F(2*n+1)=F(n+1)*F(n+1)+F(n)*F(n)
F(2*n+2)= F(n+2)*F(n+1)+F(n+1)*F(n)=(F(n+2)+F(n))*F(n+1)= (F(n+1)+F(n)*2)*F(n+1)
*/
unsigned fib_last4 ( unsigned num )
{
if ( num == 0 ) return 0 ;
const unsigned M = 10000 ;
unsigned ret = 1 , next = 1 , ret_ = ret ;
unsigned mask = 1 , tt = num ;
while ( tt >>= 1 ) mask <<= 1 ;
while ( mask >>= 1 ){
if ( num & mask ){
ret_ = ret * ret + next * next ;
next = ( ret + ret + next ) * next ;
} else {
// 多加一个M ,避免 2*next-ret 是负数,造成结果不对
ret_ = ( next + next + M - ret ) * ret ;
next = ret * ret + next * next ;
}
ret = ret_ % M ;
next = next % M ;
}
return ret ;
}
相关文章推荐
- flyinghearts《编程之美》读书笔记连载(5)
- flyinghearts《编程之美》读书笔记连载(15)
- flyinghearts《编程之美》读书笔记连载(13)
- flyinghearts《编程之美》读书笔记连载(12)
- flyinghearts《编程之美》读书笔记连载(11)
- flyinghearts《编程之美》读书笔记连载(6)-高效率安排见面会
- flyinghearts《编程之美》读书笔记连载(3)
- flyinghearts《编程之美》读书笔记连载(6)
- flyinghearts《编程之美》读书笔记连载(10)(转)
- flyinghearts《编程之美》读书笔记连载(18)
- flyinghearts《编程之美》读书笔记连载(7)
- flyinghearts《编程之美》读书笔记连载(13)
- 《编程之美》读书笔记连载(2)
- 【读书笔记】《编程之美》1.1——让CPU占用率听你指挥——四种解法
- 《编程之美》读书笔记(二):烙饼的排序问题(Java实现)
- 《编程之美》读书笔记(二): 一摞烙饼的排序问题
- 《编程之美》读书笔记(七):数独游戏解析
- 《编程之美》读书笔记21: 2.4 1的数目
- 《编程之美》读书笔记24: 3.5 最短摘要的生成
- 《编程之美》读书笔记21: 2.4 1的数目