前言
前段时间网上看到一位同学的面试分享,其中提到这个算法题,当时文章中提供了大致的思路,但没有给出完整的算法分析。
底下的评论断断续续有一些解释,但也不够具体和完整。后面经过推到思考,整理出这篇文章。
问题描述
有 15 个瓶子,每个瓶子装满了液体,其中最多有 1 个瓶子的液体有毒。现在有 4 只老鼠,如果老鼠喝到有毒的液体,一个星期后会挂掉。
现给你一个星期时间,找出有毒的瓶子。
问题分析
15 个瓶子,最多 1 个瓶子有毒,那么最多有 16 中情况。如果给 15 只老鼠分别编号为 1、2、3、4、5 ... 15,那么 16 中情况分别描述如下:
情况1:所有瓶子都无毒 情况2:编号为1的瓶子有毒,其他无毒 情况3:编号为2的瓶子有毒,其他无毒 ... 情况15:编号为15的瓶子有毒,其他无毒
老鼠喝了瓶子里面的液体后,会有两种状态,继续活着或挂掉。分别用 0(活着) 和 1(挂掉) 表示,4 只老鼠总共可以表示 16 种状态,刚好能够表示瓶子的 16 种状态。
具体操作
将编号为 1、2、3 ...15 的瓶子,转为四位的二进制数,例如: 1 -> 0001 2 -> 0010 3 -> 0011 ... 15 -> 1111
4个位置,从高位到低位分别放4只老鼠 A, B, C, D; 然后从第1个瓶子开始将瓶子里面的液体喂给四只老鼠,规则如下: 1 -> 0001 - 表示编号为1的瓶子,对应的二进制数为 0001,即将编号1的液体喂给 D 老鼠,因为老鼠的位置从高位到低位依次为 ABCD
2 -> 0010 - 表示编号为2的瓶子,对应二进制为 0010,即将编号2的液体喂给 C 老鼠。
3 -> 0011 - 表示编号为3的瓶子,对应的二进制为 0011,即将编号3的液体同时喂给 C 和 D 老鼠
...
15 -> 1111 - 表示编号为15的瓶子,对应的二进制为 1111,即将编号15的液体,同时喂给老鼠 A, B, C, D.
规则可总结为,编号对应的二进制数上,如果某一位置为1,那将这瓶液体喂给对应位置上的老鼠。这样,一周后看结果,看对应位置的老鼠状态(活着-0或挂掉-1),然后将对应的状态用 0和1表示,最好将0和1表示的二进制数转为十进制,就是对应的有毒液体瓶的编号。 例如:
- 结果为 A(0),B(0),C(1),D(1)时,对应的二进制为 0011,转为十进制为 3,表示3号瓶有毒;
- 结果为 A(0),B(0),C(0),D(0)时,对应的二进制为 0000,转为十进制为 0,表示所有瓶子都无毒;
- 结果为 A(1),B(1),C(1),D(1)时,对应二进制为 1111,转十进制为 15,表示 15 号瓶有毒;
备注:A(0)表示一周后,A 老鼠活着;C(1)表示一周后,C 老鼠挂掉了。
最后
这个问题还可以继续拓展,如:有 1023 只瓶子,最多只有一个瓶子有毒,有10只老鼠,老鼠喝了有毒瓶子里面的液体后,一周后会挂掉。请在一周后找出有毒的瓶子。
思路跟 15 个瓶子类似。