本人2年Android,最近在看机会,投了课程格子,然后沟通后要先通过一道题目,在再决定安不安排面试.
题目是一个上机题目,但是其核心(个人认为)是斐波那契数列的问题.
题目如下:
要求:
- 请实现一个可以显示斐波那列表的activity
- 请编写文档介绍你都做了那些很酷的事情
- 项目必须可以在Android SDK 4.0以上的版本与环境下运行
- 提交一个完整的,可运行的Android项目包
- 压缩打包代码和文档,命名为[名字]_android.zip
题目:
a.1.请写一个仅有一个列表页面的Android应用
a.2.列表从0开始,从小到大,每行显示一个斐波那器数字
a.3.列表第n行显示F(n^2),至少显示到F(450^2)
a.4.列表必须保持流利滑动
a.5.当数值超过10^10时,用科学计数法表示Fibonacci的值
a.6.不允许计算完所有的值之后再显示
a.7.可以使用BigInteger来存储F(n)的值
b.1.在界面上价一个切换顺序的按钮
b.2.点击按钮会在"从小达大"和"从大到小"排序之间切换.
这道题目经过思考之后,如果要满足a.3和a.4,那么计算第i行的斐波那契数列值,其时间复杂度必须要求在常数范围内.
因为我自己测试过,在使用BigInteger的非递归方法计算450行的斐波那契数列值(450*450),大约需要1秒多,因此很明显不符合题目要求:
只能从其他方面着手,经过题主2-3个小时的研究,发现了不同行数间斐波那契数列数列的规律,根据这个思路写出来的代码,计算全部450行的斐波那契数列值,仅需200ms-300ms.
个人认为绝对可以满足题目要求,并且整个工程代码复杂度也比较低.其思路如下:
如何找出f(1),f(2*2),f(3*3),f(4*4)....f(n*n)之间的计算规律.
如果找出了计算规律,实际上计算下一个目标值,只是做简单的大数相加/相乘的操作,其时间复杂度为BigInteger的计算加法和乘法的时间复杂度O(N).
另外一方面,题目要求在超过10^10值时,要以科学计数法表示,实际上就是将实际的f(n*n)的结果化为x.xxxEn的格式,
其时间复杂度也主要是BigInteger.toString()复杂度加上String.substring()的时间复杂度.
这样分析看来,整道题目的难点就在如何找到规律.
而f(1),f(2*2),f(3*3),f(4*4)....f(n*n)之间的计算规律也不难发现.
例如:
f(4) = 2 个 0 +
3 个 1
f(9) = 5 个 3 + (等于 2 + 3)
8 个 4 (等于 2 + 3 + 3)
f(16)= 13个 8 + (等于 5 + 8)
21个 9 (等于 5 + 8 + 8)
f(25)= 34个 15+ (等于 13 + 21)
55个 16 (等于 13 + 21 + 21)
f(36)= 89个24 + (等于 34 + 55)
144个25 (等于 34 + 55 + 55)
...
例如:
f(3) = 1 个 0 +
2 个 1
f(8) = 3 个 3 + (等于 2 + 1)
5 个 4 (等于 2 + 1 + 2)
f(15)= 8 个 8 + 等于(3 + 5)
13个 9 等于(3 + 5 + 5)
...
根据以上分析,发现规律后,计算新的f(n*n) (n代表行数),就可以在之前已计算出的结果之上计算,其复杂度相当低.
例如要计算f(9) = 5 * f(3) + 8 * f(4),而f(3),和f(4)的值又已经知道,所以计算f(9)仅需BigInteger的常数计算.
例如计算 f(1) 至 f(450*450) 的所有BigInteger值,仅需要200ms - 300ms(根据cpu不同,有关系.)
出来思路后,代码就很容易实现了,地址为:https://github.com/biezhihua/KeChengGeZi
整体代码写完后,兴致冲冲的将代码用邮件交给了,课程格子的HR,但是迟迟等不来消息,我就寻思莫非思路错了?
然后详细的校验了前30行,和450行的数据,均没有发现问题.然后,题主又死皮赖脸的发邮件给HR询问结果.
HR第二天给了答复,说是和技术沟通了笔试题,问题处在计算结果和正解又偏差.
此时我非常奇怪,然后再一次对结果进行的校验,同时还在网络上搜索了一些斐波那契数列的计算器.
左侧为网络上几款计算斐波那契数列数列的结果值,右侧是我计算出的结果值:
f(76) : 3416454622906707 3416454622906707
f(77) : 5527939700884757 5527939700884757
f(78) : 8944394323791464 8944394323791464
f(79) : 14472334024676220 14472334024676221
f(80) : 23416728348467684 23416728348467685
f(81) : 37889062373143900 37889062373143906
结果很清晰,其中的差别在于计算f(79)结果的时候,网络上的计算值是14472334024676220,而我的是14472334024676221.
奇怪的事情出现了,f(79)=f(78)+f(77),那么4+7=11,怎么会出来0.
得到结果的我,又向课程格子的HR发了封邮件,但是没有收到回复,内容如下:
其实面不面试也不那么重要.因为我在做这道题目的时候,对题目要求计算斐波那契数列结果校验过很多次,而且也仔细核验过在行数小于9时的结果,
与行数为450的记过.如果经过贵公司的技术官检验出我的结果有偏差,至少要说明一下我计算出整个斐波那契数列结果有问题还是只是中间部分数值有问题.
此外,这道题目并没有题目中所说的这么简单,我光发现不同行的斐波那契数列计算规律就用了接近2-3个小时,我觉得而在面试者用心回答时,
面试公司也应该对不认同的答案指出错误之处,以证明自己观点的正确.
我觉得这不仅是对贵公司面试题的负责,也是对面试者的负责,也是对公司面试流程的负责.
目前还没收到回复,但是始终心有疑问,我的思路和答案是否正确?
只能指望各位大牛回答者了