前几天面试了一家公司,给了两个算法题目。觉得挺有意思的,当时面试回答的时候回答的不太好。随后回来找了一下资料。记录一下。
一、题目一
有1000瓶水,其中有一瓶有毒,小白鼠只要尝一点带毒的水24小时后就会死亡,至少要多少只小白鼠才能在24小时时鉴别出那瓶水有毒。楼主这个题目当时没有回答出很好的方案。只想到了这个题目应该和二进制有联系。回来后在网上查找了一下资料,既然有如此精妙的想法。
给1000个瓶分别标上如下标签(10位长度):
0000000001 (第1瓶)
0000000010 (第2瓶)
0000000011 (第3瓶)
......
1111101000 (第1000瓶)
从编号最后1位是1的所有的瓶子里面取出1滴混在一起(比如从第一瓶,第三瓶,。。。里分别取出一滴混在一起)并标上记号为1。以此类推,从编号第一位是1的所有的瓶子里面取出1滴混在一起并标上记号为10。现在得到有10个编号的混合液,小白鼠排排站,分别标上10,9,。。。1号,并分别给它们灌上对应号码的混合液。24小时过去了,过来验尸吧:
从左到右,死了的小白鼠贴上标签1,没死的贴上0,最后得到一个序号,把这个序号换成10进制的数字,就是有毒的那瓶水的编号。
检验一下:假如第一瓶有毒,按照0000000001 (第1瓶),说明第1号混合液有毒,因此小白鼠的生死符为0000000001(编号为1的小白鼠挂了),0000000001二进制标签转换成十进制=1号瓶有毒;假如第三瓶有毒,0000000011 (第3瓶),第1号和第2号混合液有毒,因此小白鼠的生死符为00000011(编号为1,2的鼠兄弟挂了),0000000011二进制标签转换成十进制=3号瓶有毒。
二、题目二
有n个人,其中一个明星和n-1个群众,群众都认识明星,明星不认识任何群众,群众和群众之间的认识关系不知道,现在如果你是机器人R2T2,你每次问一个人是否认识另外一个人的代价为0(1),试设计一种算法找出明星,并给出时间复杂度。楼主当时回答出来了双重循环的哪种情况。但是那种情况的时间复杂度是O(N*N)。
解法一:看到题目后,首先想到的是任选其中一个人作为目标对象,然后询问剩下的n-1个人。若当前目标不认识其他人,但是其他人认识ta,则目标就是明星,否则,目标不是明星,在选择其他人作为目标做同样的询问。时间复杂度为O(N*N).
解法二: 在解法一中,每次只是做了询问而没有记录相关的信息,比如在询问A和B时,有以下几种关系:
1) A不认识B, B不认识A。==> A和B都不是明星
2)A认识B, B认识A。==> A和B都不是明星
3) A认识B, B不认识A。==> A不是明星,B可能是明星。
4)A不认识B, B认识A。==> A可能是明星,B一定不是明星
因为每次询问都可以至少排除一个对象,因此只需要n-1次询问即可找到目标。
总结如下:is A 认识 B? (yes) A不是明星,B可能是明星 : (no) A可能是明星,B是群众。所以一次询问可以确定一个人
1 int func38(int a[], int n) 2 { 3 int i; 4 int stari = 0; //存放最小数在a中的位置 ,明星的位置 5 int flag = 0; 6 7 for (i=1; i<n; i++) 8 { 9 if(a[stari] > a[i])//如果stari标号的数小于i标号的数, 表示a[stari] 认识 a[i] 10 { 11 stari=i; 12 flag=0; //更换怀疑对象(最小数)时,标记清零 13 } 14 else if(a[stari] ==a[i]) //如果stari里存放的确实是唯一最小数是不会跑进这里来的 15 { 16 flag++; 17 } 18 } 19 if(flag>0) 20 return -1;//表示没有明星,例如所有的数都相等 21 22 return stari; 23 }
参看:
http://lzj0470.iteye.com/blog/657579
http://www.cnblogs.com/legendmaner/archive/2013/05/24/3097248.html