快与慢 0

快与慢 0

a、老板让你最快的计算 f(N) = 13+23+…+N3。逐项计算当然是可以的,如果能直接算出来当然会大大加快电脑计算的速度。

实际上f(N) = (1+2+…+N)2 = N2*(N+1)2/4

 

bJosephus(约瑟夫)问题。这是个老生常谈的话题,大意如下:

已知n个人(以编号123...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列。

1,用循环链表。

2,获得递推公式。t表示约瑟夫环中人数,J(t)表示在t人中的胜利者。

n个人编号01、……、n-1J(t) = (J(t-1) + m%t)%t = (J(t-1) + m)%t.,且J[1] = 0;最终结果为J[n] +k

 

c、老板让你编个程序,以最快的速度计算50以下数的阶乘(比如15!)。如果以前遇到过这个问题或者思维缜密,会在考虑一些问题后可以写出一个程序,考虑的问题先后有:

1、  根据阶乘的定义用一个迭代实现。当然你首先会考虑到n!在n相当大的时候可以用stirling公式去逼近,

          ____

n! ~ √ 2πn  (n/e)n   

很不幸这个近似公式在n-> +∞时实际值与近似值比值为1。不过你想至少可以用stirling来做测试近似检验算法是否正确。

2、但是即使是13!都超过了32位表达范围。所以不管是用迭代、直接连乘还是stirling都存在这个问题——上溢。你想到要组织一个自己的记录大数的结构

3、用数组吧。构造一个长度为m数组假设足够长能容纳结果,数组的index0m的字节表示位权从20— 2 m -1

2m -1

……

213

212

211

210

29

28

27

26

25

24

23

22

21

20

 

 

0

9

8

7

6

5

4

3

2

1

2

3

4

5

比如表格里的数表示9876543212345。(题外话,在这里想起一个比较好玩的数1111111112 = 12345678987654321

4、根据这个记录数据的结构,设计乘法操作,比如对9876543212345 * 15,把15与每位的乘积保存,再加上上一位的进位,除以10的商用作下一位的进位;模10的结果作为这位的值。

       unsigned int carry = 0u;

       unsigned int mul = Num[i] * 15u + carry;

       carry = mul/10u;

       mul /= 10u;

       Num[i] = mul;

还要计算数组到底需要多大才能容纳这个阶乘值。

n≤ 10 m ;两边取对数 log10n + log10 (n-1) +…+ log10 (2) ≤ m,对m做天花板(很形象的名称)操作┌m┐,最好再加上1个字节,担心在取对数时会有微小精度损失。

5、程序写完后应该检验与实际结果是否吻合,于是你打开matlabmathematica或者os自带的计算器验证,发现结果正确。这时你才发现已经过了好几个钟头,黄花菜都凉了,而老板只是要你算很少几个数的阶乘。是的,你只要用计算器算出结果告诉他就行,可以事先算出来硬联编到程序中,很多快速算法都是类似的建表的思路。(FFT

建表只是现象,本质是更简单更清晰地解决问题。我经常学了算法后反而笨手笨脚了。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值