最近看了不少关于求职面试的试题,在其中发现了不少有意思的题目。特整理后发表上来与大家一起分享。
为了方便与以后添加的题目区别,每次更新会以 A 、 B…… 的方式标注。
A-1 : 如何将 a 、 b 的值进行交换,并且不使用任何中间变量?
解析:一般可以选择两种方式:
( 1 )使用加法运算: a = a+b; b = a-b; a = a-b;
( 2 )使用异或运算: a = a^b; b = a^b; a = a^b;
其中,如果 a 、 b 的值比较大,那么选择第一种方式可能会导致越界,因此,最佳答案是异或方式。
A-2 : main 主函数执行完毕后,是否可能会再执行一段代码?
解析:回答是肯定的。可以使用 atexit() 函数注册一个函数,使得主函数在退出前先执行该注册地函数。
A-3 : 写出下面程序的运行结果
解析:据说这是一个很好的概率题。该题中暗含了一个 1/4 圆和一个正方形比较大小的问题。其中,RAND_MAX 是随机数中的最大值,也就是相当于最大半径 R ;而 x 、 y 值则相当于横纵轴的坐标值,它们的平方和开根号就是原点到该点 (x, y) 的距离,当然这个距离可能大于 R 也有可能小于 R 。
通过上面的分析,该问题则可以蜕化为:随机在正方形里落 LOOP 个点,落在半径里面的点有多少个。鉴于 1/4 圆面积是 (1/4)*π*R*R ,正方形面积是 R*R ,两者之比为 (1/4)*π ,所以落点数为 LOOP*(1/4)*π 个。鉴于题意中 LOOP 为 1000 ,则可计算出大约为 785 个点。
然而,我在 Linux ubuntu 2.6.24-22-generic 运行该程序得到的结果却是 500 左右, Why ?
A-4 :写出下列程序的执行结果:
解析:首先 5 为 int 型,在 32 平台上会由编译器分配 4 个字节;当以 %f 方式输出时,编译器将从该值所在地址上读出 8 个字节。很显然地,内存访问越界,因此输出结果不确定。同理以 %d 方式显示浮点数 5.01时,结果也将不确定。从实际测试来说,第一个答案往往是 0.000000 ;第二个很可能是大数。
A-5 : 写出下面程序的执行结果:
解析:该程序主要考察内存中数据如何存储。在冯 · 诺依曼体系中,在内存中数据的低位字节存储在低地址上;而数据的地址则采用它的低地址来表示,具体情况如下所示:
因此该结果将是: f0f1f2f3 , f3 。
B-1 : 写出下面程序的执行结果:
解析:这是一个典型的溢出问题。首先数组 s 被分配了 11 个字符(包含字符串串尾的空字符),而数组 d 只被分配了 4 个字符;所以当使用 strcpy() 函数进行字符串复制时,数组 d 会溢出。由于数组 s 和d 都是自动变量,它们存在于 stack 中,而数组 s 先被分配在高地址上,而数组 d 则被分配在后续的低地址上,当数组 d 越界时,则会造成数组 s 中的数据被覆盖,原来的“ 123456789 ” 则被覆盖为“ 56789/0789 ” ,其中 ’/0’ 代表字符串尾的空字符。
因此,该输出应该是 123456789 , 56789 。
C-1 :按下面矩阵的输出写出相应的程序:
n=5:
1 2 9 10 25
4 3 8 11 24
5 6 7 12 23
16 15 14 13 22
17 18 19 20 21
n=6:
1 2 9 10 25 26
4 3 8 11 24 27
5 6 7 12 23 28
16 15 14 13 22 29
17 18 19 20 21 30
36 35 34 33 32 31
解析:这是网易有道的一道面试题。貌似在面试中这种类型的题目不少,之前在我的博客中就有一篇关于螺旋队列 的解析。如果你仔细观察上述输出,就会发现从 1 开始按照大小会排列成蛇形,那么我们姑且把该题目叫做蛇形队列 的算法设计。
如果你是第一次接触这种类型的题目,可以看一下博客中关于 螺旋队列 的解析,这里只写出关键的部分。假定 1 值点所在坐标为 (0, 0 ),横向为 x 轴,以向右为正;纵向为 y 轴,以向下为正。对于任一点(x, y) ,记 x 与 y 中的绝对值最大者为 A :
(1) 若 A 等于 x 的绝对值。当 A 为奇数时,输出 A 2 +y+1 ;否则,输出 (A+1) 2 -y 。
(2) 若 A 等于 y 的绝对值。当 A 为奇数时,输出 (A+1) 2 -x ;否则,输出 A 2 +x+1 。
C-2 : 36 匹马赛跑,跑道同时只能容许 6 匹马。而且 36 匹马速度不同,但是每次跑的速度恒定。问,跑多少次可以选出第一,第二,第三名。
解析:这同样是网易有道的一道笔试题。在网上已经有不少解答,这里总结一下各种方法:
( 1 ) 6 次。 36 匹马,每 6 匹一组,对六次赛跑的结果分析,从而得出结论。这是最有争议的办法,但如果从出题者的角度看,这种方法显然无法通过。
( 2 ) 11 次。 36 匹马,第一组 6 匹马赛完后,淘汰后三名;从剩下的 30 匹马中任选 3 匹进行第二轮,如此循环 … … 1+30%3 = 11
( 3 ) 8 次。 36 匹马,每 6 匹一组,赛完后取每组的第一名进行第七场赛跑,记录该次比赛的前三名。继而取第一名所在组的第二、第三名,第二名所在组的第一、第二名,第三名所在组的第一、第二名进行第八场赛跑,得出前两名。最终得到结论。
第三种方法最切合出题者的意图。然而如果说裁判的记忆力很差,只能记住一场比赛的结果时,那么显然第三种方法便不是正解了;如果裁判可以记录,那么第一种办法则成为最优解。所以,我认为这个题目本身有多种解答,应该就具体情况具体分析。
C-3 :给定一个字串 X ,求它最长字串 S ,使得 S=SR , SR 为 S 的反序,即如果 S=abc ,则 SR=cba。比如: X=abccba ,则输出 S=abc 。
解析:这是一个典型的查找回文的题目。下面是我自己编写的一个处理程序:
D-1 : 在一个火车站:每 10 分钟就有一火车离站向南开去;每 10 分钟,也有另外一辆火车离站向北开去。每天,你到达这个火车站的时间并不是固定的(换言之,在时间上你是随机到达火车站的)。但是在你每次到达以后,你就会乘坐最先到站的火车离开,而不管它是往北或者是往南开。这样在乘坐了一年以后,你发现在90% 的天数里,你所乘坐的是南行的火车。请问这是为什么?
解析:答案是“南行的火车时间比北行的时间早 1 分钟”。这是一道概率题。我们考虑连续两次向南发车时间点 a 、 b 之间的时间段,在这个时段内肯定会在某个时刻向北发一次车,该时间点我们记为 c 。考虑到每次到火车站后会选择最先到站的火车离开,那么在 a 、 b 间的时间段内,选择向北火车的概率是 (c-a)/(a-b)*100% 。当我们把目光从 a 、 b 间的时间段扩展到整一天时,该结论同样正确。所以,当你发现 90% 的天数中乘坐的是南行的火车时,即有 (c-a)/(10min)*100%=(1-90%) 成立,易得“南行的火车时间比北行的时间早 1分钟”。
D-2 :有两个数组 a,b ,大小都为 n, 数组元素的值任意,无序。要求通过交换 a,b 中的元素,使数组 a 元素的和与数组 b 元素的和之间的差最小。
解析:这是华为的一道面试题,要求在 8 分钟内解决。一种简单可行的方案是遍历查询(也就是穷举法),对于 A 、 B 数组中的数据存放在一个数组 Data 中,假设两个数组各有 NUM 个元素。那么我们在Data 数组中选择有 NUM 个元素的所有情况(使用组合代数),计算选出子数组的和与未选数据的和之间的差值。记录最小差值的情况,然后显示之。
当然,这种方案显然不是最优解,但是确实有个可行的方案。(其实,我认为即使使用该方案在 8 分钟内实现 C 代码也是不现实的,除非是伪代码)。 Chinaunix 论坛上 有一帖子 专门讨论它,有兴趣的朋友可以去看看。下面给出我写的实现代码
E-2 :将 1,2,3,4,5,6,7,8,9 共 9 个数分成三组 , 组成 3 个三位数 , 且使这 3 个三位数构成 1:2:3 的比例 , 例如 :3个三位数 192,384,576 满足以上条件 .192:384:576=1:2:3 。试求出所有满足条件的 3 个三位数。
解析: 1 ~ 9 组成的最小三位数是 123 ,最大的是 987 ,由于要满足 1 : 2 : 3 的关系,最小的那个数应该不到于 987/3 = 329 。这个问题的求解可以对每个数 n(123<=n<=329) 使用枚举法。
对于每种情况,鉴于只是需要判断这三个数是否由 1~9 组成且各个数组不相同,即这三个数的各位数是否覆盖了1~9 ,那么一种合理的解法是判断各位数字的积是否等于 9 !且各位数字的和是否等于 45 。
在我自己写的程序中,使用的方法是对三个数的每位上的数做简单加法,平方和以及立方和;继而与 45 、 285和 2025 比较。实现如下: