算法学习之二进制的妙用

有一个笑话,世界上有10种人,一种是看得懂二进制的,一种是看不懂的。 若是你看懂了这个笑话,这篇文章就是适合你读的了javascript

Single Number

leetcode 上有一道这样的题,Single Number,题目是要你要找到数组中惟一只存在一个的数字,其余数字都出现两次。这道题目很是的简单,咱们能够用 hash 表来记录全部数字的次数,而后找到次数为1的那个数字。若是用二进制来解决这道题效率会快不少。java

二进制的解法

二进制中有一个操做符叫作位异或,他的做用是两个位数字相同则为0,不一样则为1,即 1^1=0,0^0=0,1^0=1,0^1=1;数组

经过这个运算符的特色咱们能够知道,任何一个数对本身位异或操做,获得的结果都是 00000000,00000000对任意数字位异或获得的都是那个数字。而且 A ^ B ^ C = C ^ B ^A,这个操做符是知足交换律的。下面看一下 js 的简单解法:spa

/** * @param {number[]} nums * @return {number} */
var singleNumber = function(nums) {
    return nums.reduce((res, cur) => res ^ cur);
};

复制代码

毒药问题

有 8 个如出一辙的瓶子,其中有 7 瓶是普通的水,有一瓶是毒药。任何喝下毒药的生物都会在一星期以后死亡。如今,你只有 3 只小白鼠和一星期的时间,如何检验出哪一个瓶子里有毒药?code

解决思路

咱们用二进制给每瓶水进行编号,编号分别为,000,001,010,011,100,101,110,111,分别对应1-8的瓶子,而后让第一只老鼠喝第一位为1的,第二只老鼠喝第二位为1的,第三只老鼠喝第三位为1的,假设第四瓶水有毒,即011有毒ip

  • 第一只老鼠喝了 100,101,110,111,结果:没死,记做0
  • 第二只老鼠喝了 010,011,110,111,结果:死了,记做1
  • 第三只老鼠喝了 001,011,101,111,结果:死了,记做1

根据死亡结果,恰好是第四瓶水011,这只是一个巧合吗,恐怕不是的,咱们能够用数学的思惟来证实一下这个问题leetcode

证实

每只老鼠喝了毒药只会出现两种状况死或者不死,一只老鼠能够验证两瓶药有没毒,即2^1,两只老鼠能够验证2^2瓶药,三只老鼠能够验证2^3瓶药,那么要怎么去验药呢get

  • 咱们让每只老鼠喝某一位为1的的全部药,若是那只老鼠死了则说明毒药的某一位编号为1,比方说第一只老鼠喝了全部第一位为1的毒药死了,则说明毒药的第一位编号为1,若是没死,则说明毒药的那一位编号为0
  • 这里若是三只老鼠都没死,则说明毒药的三位编号都为0,恰好是三只老鼠都每没喝的第一瓶。

拓展问题

有 1000 个如出一辙的瓶子,其中有 999 瓶是普通的水,有一瓶是毒药。任何喝下毒药的生物都会在一星期以后死亡。如今,你只有 10 只小白鼠和一星期的时间,如何检验出哪一个瓶子里有毒药?数学

根据上面的问题,咱们可以知道 2 ^ 10 = 1024 > 1000,也是经过对每一个瓶子进行二进制编号便可检验出哪一个瓶子有毒。hash

问题升级

如今,有意思的问题来了:若是你有两个星期的时间,为了从 1000 个瓶子中找出毒药,你最少须要几只老鼠?注意,在第一轮实验中死掉的老鼠,就没法继续参与第二次实验了。

拓展问题思路

咱们要达到的目的是用尽量少的老鼠,在两周以内找到结果,因此咱们必需要进行两轮的实验,那么每只老鼠可能就会出现三种状况,第一轮死掉,第二轮死掉,第二轮活着,上面一题老鼠会出现两种状况用的是二进制,那么这一题很明显咱们须要用到三进制。3 ^ 6 = 729, 3 ^ 7 = 2187, 很明咱们至少是须要7只老鼠。

如何喂药

  • 仍是和前面同样,第一轮的时候,咱们让每只老鼠喝某一位为编号为2的药,若是某只老鼠死了,则说明毒药的那一位编号为2,若是老鼠全死了,咱们连第二轮都不用了,直接能够肯定毒药的编号为2222222。
  • 第二轮若是还剩多少只老鼠,则说明毒药有多少位的编号为0或者1,咱们剩k只老鼠,k位二进制数须要确认,由于那几位数已经排除了是2的可能性。则由回到了上一题,咱们继续用上一轮的喂法便可。

称重问题

27个小球。其中一个比其余小球都要重一点。给你一个天平,最多称3次,找出这个特殊的小球。

思路

这题也是须要用到三进制的思路来解决的,咱们每次称可能出现三种状态左边重,右边重,同样重,3 ^ 3 恰好27,因此咱们是能够在3次内找到这个小球。

如何称

先给每一个球编号000,001,002,010,...,222

  • 第一次称第一位为2的和第一位为1的全部小球,他们一样都是9个,哪边重则说明,较重的小球的第1为几,若是同样重则说名第一位为0
  • 第二次称第二位为2的和第二位为1的全部小球,他们也一样都是9个,哪边重则说明,较重的小球的第2位为几,若是同样重则说名第二位为0
  • 第三次称第三位为2的和第三位为1的全部小球,他们也一样都是9个,哪边重则说明,较重的小球的第3位为几,若是同样重则说名第三位为0

通过三次称重咱们就能够找到较重的哪个小球了。

总结

面对这种问题,其实解决思路都大通小异,都是须要找到问题关键状态,经过关键状态的数量咱们能够知道须要用到多少进制来解决问题。而后根据题目制定方案,来肯定每一位的状态码最终获得结果。

相关文章
相关标签/搜索