趣味面试题(二)

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 <stdio.h>    
  2. #include <stdlib.h>    
  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<n;++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<n;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<NUM;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<NUM*2;i++)  
  60.                 if(i<NUM)  
  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 <stdio.h>  
  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. }  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值