趣味面试题

趣味面试题集锦


最近看了不少关于求职面试的试题,在其中发现了不少有意思的题目。特整理后发表上来与大家一起分享。

为了方便与以后添加的题目区别,每次更新会以 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 : 写出下面程序的运行结果

[cpp]  view plain copy
  1. #include   
  2. #include   
  3.    
  4. #define LOOP 1000  
  5.    
  6. int main()  
  7. {  
  8.         int count = 0,i;  
  9.         int x,y;  
  10.    
  11.         srand(time(0));  
  12.         for(i=0;i
  13.                 x = rand();  
  14.                 y = rand();  
  15.                 if(x*x+y*y < RAND_MAX*RAND_MAX)  
  16.                         count++;  
  17.         }  
  18.    
  19.         printf("%d/n", count);  
  20.    
  21.         return 0;  
  22. }  

解析:据说这是一个很好的概率题。该题中暗含了一个 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 :写出下列程序的执行结果:

[cpp]  view plain copy
  1. #include   
  2.    
  3. int main()  
  4. {  
  5.         printf("%f/n", 5);  
  6.         printf("%d/n", 5.01);  
  7.    
  8.         return 0;  
  9. }  

解析:首先 5 为 int 型,在 32 平台上会由编译器分配 4 个字节;当以 %f 方式输出时,编译器将从该值所在地址上读出 8 个字节。很显然地,内存访问越界,因此输出结果不确定。同理以 %d 方式显示浮点数 5.01时,结果也将不确定。从实际测试来说,第一个答案往往是 0.000000 ;第二个很可能是大数。

 

A-5 : 写出下面程序的执行结果:

[cpp]  view plain copy
  1. #include   
  2. using namespace std;  
  3.    
  4. union {  
  5.         unsigned char a;  
  6.         unsigned int i;  
  7. } u;  
  8.    
  9. int main(void)  
  10. {  
  11.         u.i = 0xf0f1f2f3;  
  12.          
  13.         cout<
  14.         cout<int(u.a)<
  15.    
  16.         return 0;  
  17. }  

解析:该程序主要考察内存中数据如何存储。在冯 · 诺依曼体系中,在内存中数据的低位字节存储在低地址上;而数据的地址则采用它的低地址来表示,具体情况如下所示:  

因此该结果将是: f0f1f2f3 , f3 。

 

 

B-1 : 写出下面程序的执行结果:

[cpp]  view plain copy
  1. #include   
  2. #include   
  3.    
  4. int main(void)  
  5. {  
  6.         char s[] = "123456789";  
  7.         char d[] = "123";  
  8.    
  9.         strcpy(d,s);  
  10.         printf("%s, %s/n", d, s);  
  11.    
  12.         return 0;  
  13. }  

解析:这是一个典型的溢出问题。首先数组 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 +y+1 ;否则,输出 (A+1) -y 。

(2)       若 A 等于 y 的绝对值。当 A 为奇数时,输出 (A+1) -x ;否则,输出 A +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 。

解析:这是一个典型的查找回文的题目。下面是我自己编写的一个处理程序:

[cpp]  view plain copy
  1. #include   
  2. #include   
  3.    
  4. int main(void)  
  5. {  
  6.         char in[100];          // 最大处理限长99个字符  
  7.         int i,j,max,temp;  
  8.         char *p, *tp;  
  9.    
  10.         printf("Please input string[len<99]: /n");  
  11.         scanf("%s", in);  
  12.    
  13.         max = 0;  
  14.         p = NULL;  
  15.         for(i=1;i
  16.                 if(in[i-1] == in[i]){  
  17.                         temp = 1;  
  18.                                                      // 查找当前情况下可能的最大回文串  
  19.                         for(j=2;(i-j)>=0 && (in[i-j]==in[i+j-1]);j++,temp++);  
  20.                                                      // 如果有更大的回文字串,则更新max和  
  21.            if(temp > max){  
  22.                                 max = temp;  
  23.                                 p = &in[i];  
  24.                         }  
  25.                 }  
  26.                 if((i+max) > strlen(in))  
  27.                         break;  
  28.         }  
  29.         for(tp=p-max;tp
  30.                 printf("%c",*tp);  
  31.         printf("/n");  
  32.    
  33.         return 0;  
  34. }  



 

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 论坛上 有一帖子 专门讨论它,有兴趣的朋友可以去看看。下面给出我写的实现代码

[cpp]  view plain copy
  1. #include     
  2. #include     
  3.    
  4. #define NUM 10  
  5.    
  6. int A[NUM] = {11, 20, -3, 123, 18, 19, 171, 19, 123, 10};  
  7. int B[NUM] = {1, 23, 19, 41, 39, 123, 190, 238, 179, 25};    
  8.    
  9. int Data[NUM*2];    // 包含了数组A和B中的所有元素  
  10. int Data_inc[NUM];   // 保存了从Data数组中选出的NUM个元素  
  11. int Data_temp[NUM];  // 记录了当前能产生差值最小情况的NUM个元素  
  12.    
  13. void Print(int *a, int n){    
  14.         int i;    
  15.         for(i=0;i
  16.                 printf("%d ",a[i]);    
  17.         printf("/n");    
  18. }    
  19.      
  20. int get_sum(int *a, int n){  
  21.         int sum,i;  
  22.    
  23.         for(sum=0,i=0;i
  24.                 sum += a[i];  
  25.    
  26.         return(sum);  
  27. }  
  28.    
  29. static int diff = 0;    // 保存了当前的最小差值  
  30. static int counter = 0;   // 记录穷举的次数  
  31. void Handle(int sum){  
  32.         int sum0, sum1, i;  
  33.                   // 寻找最优情况,并记录之  
  34.         sum0 = get_sum(Data_inc, NUM);  
  35.         sum1 = sum - sum0;  
  36.         if(counter==0 || diff > abs(sum0-sum1)){  
  37.                 diff = abs(sum0-sum1);  
  38.                 for(i=0;i
  39.                         Data_temp[i] = Data_inc[i];  
  40.         }  
  41.         counter++;  
  42. }  
  43.    
  44. void Com(int n, int m, int sum){    
  45.         int i;     // 使用组合算法从Data数组中选出NUM个元素保存在Data_inc数组中  
  46.         for(i=n;i>=m;--i){        //  抽屉子算法  
  47.                 Data_inc[m]=Data[i];    
  48.         if(m>0)    
  49.                 Com(i-1,m-1, sum);    
  50.         else    
  51.                 Handle(sum);    
  52.       }    
  53. }    
  54.    
  55. int main()    
  56. {    
  57.         int i;  
  58.    
  59.         for(i=0;i
  60.                 if(i
  61.                         Data[i] = A[i];  
  62.                 else  
  63.                         Data[i] = B[i-NUM];  
  64.    
  65.         printf("Sum in A: %d, Sum in B: %d/n", get_sum(A, NUM), get_sum(B, NUM));  
  66.         Print(Data, NUM*2);  
  67.    
  68.         Com(NUM*2-1,NUM-1, get_sum(Data, NUM*2));  
  69.    
  70.         Print(Data_temp, NUM);  
  71.         printf("Diff Value is %d, Count %d. /n", diff, counter);  
  72.        
  73.         return   0;    
  74. }     

 

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 比较。实现如下:

[cpp]  view plain copy
  1. #include   
  2.    
  3. int judge2(int a, int b, int c){     // 满足返回0,否则返回1  
  4.         int x[3] = {a, b, c};  
  5.         int i, value0, value;  
  6.         int sum, sum2, sum3;  
  7.    
  8.         sum = sum2 = sum3 = 0;  
  9.         for(i=0;i<3;i++){  
  10.                 value0 = x[i];  
  11.                 do{  
  12.                         value = value0 % 10;  
  13.                         sum += value;  
  14.                         sum2 += value * value;  
  15.                         sum3 += value * value * value;  
  16.                 }while(value0 = value0 / 10);  
  17.         }  
  18.    
  19.         if(sum==45 && sum2==285 && sum3==2025)  
  20.                 return 0;  
  21.    
  22.         return 1;  
  23. }  
  24.    
  25.    
  26. int main()  
  27. {  
  28.         int a,b,c;  
  29.    
  30.         for(a=123;a*3<987;a++){  
  31.                 b = a*2;  
  32.                 c = a*3;  
  33.                 if(!judge2(a, b, c))  
  34.                         printf(" %d : %d : %d/n", a, b, c);  
  35.         }  
  36.    
  37.         return 0;  
  38. }  

 


你可能感兴趣的:(others)