面试题系列 (一) 算法
2009-06-26 16:41
239 查看
声明:所有题目均来自网络,非本人亲历试题,且本人不透露自己亲历面试笔试试题。
如若本文侵权,告知本人后我将立即删除。
泰波拿契數 (Tribonacci Number) 即把費波拿契數 (Fibonacci Number) 的概念推廣至三個數。
T0
= 0, T1
= T2
= 1, Tn
= Tn-1
+ Tn-2
+ Tn-3
请你写一个算法,输入n,输出第n个Tribonacci数mod 2009的结果。
这个题目是众多名企的笔试面试题,据我所知,2009年微软海笔就出了这个题。另外据说google也出国这个题目。这个题目的好,好在于它有很好的区分度。
这个题目有三种解法。你采用什么算法,你的水平就一目了然了。
首先看第一种解法,也是最简单,最容易想到的。
递归法:代码如下:
采用递归的方法需要大量的重复计算。
经过测试,在ubuntu + gcc -o + p4 2.4GHz的机器上,100都需要算好久。
如果你采用这种算法的话,毫无疑问。你是不可能PASS笔试的。
算法二:采用递推的方法:
这种方法也很简单,头文件定义的宏已经在上面代码有了,函数代码如下:
采用递推的算法消除了很多重复计算,其时间复杂度是线性的,只扫描一遍O(n).
经测试,一百万以内的数字可以瞬间得到答案。1千万的话也能在1秒内得到解。但是超过1千万就不行了。
在笔试的时候,由于时间有限,其实能写到这个算法就应该可以勉强过笔试了。
第三种解法,矩阵法:
我们首先对算式做一个预处理:
Tn
= Tn-1
+ Tn-2
+ Tn-3
Tn+1
= Tn
+ Tn-1
+ Tn-2
=Tn-1
+ Tn-2
+ Tn-3 + Tn-1
+ Tn-2
= 2Tn-1
+2Tn-1
+ Tn-2
Tn+2
= Tn+1
+ Tn
+ Tn-1
= 4Tn-1
+3Tn-1
+ 2Tn-2
根据上面的变形,我们可以写成矩阵乘法的方式:
[Tn+2, [ 4 , 3 , 2 ; [Tn-1,
Tn+1, = 2 , 2 , 1; * Tn-2,
Tn] 1, 1 , 1] Tn-3];
我们分别令三个矩阵为 C B A,则有 Cn+2 = B * An-1
因此Cn+5 = B * Cn+2 = B * B * An-1
依此类推 Cn + k = B ^ ([(k + 1) / 3]) * An-1 其中[]为向上取整
于是我们成功将模型转化为矩阵连乘了,而矩阵连乘是符合结合律的,因此我们可以二分求解.
算法复杂度转化为O(logn),具体代码如下:
code写得有点烂,多包涵
第三种方法是最完美的,但是代码量比较大,而且容易写错。在面试的时候倒是可以拿出来show一把自己的算法功底。
如若本文侵权,告知本人后我将立即删除。
泰波拿契數 (Tribonacci Number) 即把費波拿契數 (Fibonacci Number) 的概念推廣至三個數。
T0
= 0, T1
= T2
= 1, Tn
= Tn-1
+ Tn-2
+ Tn-3
请你写一个算法,输入n,输出第n个Tribonacci数mod 2009的结果。
这个题目是众多名企的笔试面试题,据我所知,2009年微软海笔就出了这个题。另外据说google也出国这个题目。这个题目的好,好在于它有很好的区分度。
这个题目有三种解法。你采用什么算法,你的水平就一目了然了。
首先看第一种解法,也是最简单,最容易想到的。
递归法:代码如下:
#include <iostream> #include <fstream> #include <cstdlib> using namespace std; #define THRESHOLD 2009 #define DEAL(x) ((x) < THRESHOLD ? (x) : (x) % THRESHOLD) int tribonacci_v1(int n) { if (n <= 2) return n == 0 ? 0 : 1; else { int k = tribonacci_v1(n - 1) + tribonacci_v1(n - 2) + tribonacci_v1(n - 3); return DEAL(k); } }
采用递归的方法需要大量的重复计算。
经过测试,在ubuntu + gcc -o + p4 2.4GHz的机器上,100都需要算好久。
如果你采用这种算法的话,毫无疑问。你是不可能PASS笔试的。
算法二:采用递推的方法:
这种方法也很简单,头文件定义的宏已经在上面代码有了,函数代码如下:
int tribonacci_v2(int n) { int res[] = {0,1,1,2}; for (int i = 3;i <= n;i++) { res[3] = res[2] + res[1] + res[0]; res[3] = DEAL(res[3]); res[0] = res[1]; res[1] = res[2]; res[2] = res[3]; } return n <= 2 ? res : res[2]; }
采用递推的算法消除了很多重复计算,其时间复杂度是线性的,只扫描一遍O(n).
经测试,一百万以内的数字可以瞬间得到答案。1千万的话也能在1秒内得到解。但是超过1千万就不行了。
在笔试的时候,由于时间有限,其实能写到这个算法就应该可以勉强过笔试了。
第三种解法,矩阵法:
我们首先对算式做一个预处理:
Tn
= Tn-1
+ Tn-2
+ Tn-3
Tn+1
= Tn
+ Tn-1
+ Tn-2
=Tn-1
+ Tn-2
+ Tn-3 + Tn-1
+ Tn-2
= 2Tn-1
+2Tn-1
+ Tn-2
Tn+2
= Tn+1
+ Tn
+ Tn-1
= 4Tn-1
+3Tn-1
+ 2Tn-2
根据上面的变形,我们可以写成矩阵乘法的方式:
[Tn+2, [ 4 , 3 , 2 ; [Tn-1,
Tn+1, = 2 , 2 , 1; * Tn-2,
Tn] 1, 1 , 1] Tn-3];
我们分别令三个矩阵为 C B A,则有 Cn+2 = B * An-1
因此Cn+5 = B * Cn+2 = B * B * An-1
依此类推 Cn + k = B ^ ([(k + 1) / 3]) * An-1 其中[]为向上取整
于是我们成功将模型转化为矩阵连乘了,而矩阵连乘是符合结合律的,因此我们可以二分求解.
算法复杂度转化为O(logn),具体代码如下:
code写得有点烂,多包涵
void MatrixMul(int res[][3],const int m1[][3],const int m2[][3]) { int tmp[3][3]; memset (tmp, 0, sizeof(tmp)); for (int i = 0;i < 3;i++) { for (int j = 0;j < 3;j++) { for (int k = 0;k < 3;k++) { tmp[i][j] += m1[i][k] * m2[k][j]; } tmp[i][j] = DEAL(tmp[i][j]); } } memcpy(res, tmp, sizeof(int) * 9); } int tribonacci_v3(int n) { if (n <= 2) return n == 0 ? 0 : 1; int matrix[3][3] = { 4 , 3, 2, 2 , 2, 1, 1 , 1, 1}; int res[3][3] = { 1 , 0 , 0, 0 , 1 , 0, 0 , 0 , 1}; int pow = n / 3; int index = 2 - n % 3; while (pow != 0) { if (pow & 1) MatrixMul(res, res, matrix); MatrixMul(matrix,matrix,matrix); pow >>= 1; } return DEAL(res[index][0] + res[index][1]); }
第三种方法是最完美的,但是代码量比较大,而且容易写错。在面试的时候倒是可以拿出来show一把自己的算法功底。
相关文章推荐
- 白话经典算法系列之十 一道有趣的GOOGLE面试题
- 白话经典算法系列之十 一道有趣的GOOGLE面试题
- 【白话经典算法系列之十二】数组中只出现1次的两个数字(百度面试题)
- 算法系列-大数据面试题-两个大文件中找出共同记录
- iOS面试题系列之常见算法
- 经典算法面试题系列(一)——tow sum
- 【白话经典算法系列之十一】一道有趣的GOOGLE面试题 --【解法2】
- 经典基础算法之面试题(系列一)(转)
- 【BAT经典算法面试题系列】求和为n的连续正整数
- 算法系列-大数据面试题-大文件中返回频数最高的100个词
- 经典算法面试题系列 (二)——three sum
- 白话经典算法系列之十 一道有趣的GOOGLE面试题
- 【白话经典算法系列之十二】数组中只出现1次的两个数字(百度面试题)
- 算法系列-大数据面试题-在超大文件中找出访问百度次数最多的IP
- 【白话经典算法系列之十二】数组中只出现1次的两个数字(百度面试题)
- 经典算法研究系列:三、动态规划算法解微软一道面试题[第56题]
- 白话经典算法系列之十 一道有趣的GOOGLE面试题
- [Swift]面试题系列之常见算法
- 白话经典算法系列之十 一道有趣的GOOGLE面试题
- iOS面试题系列之常见算法