一.
有
15
个瓶子,其中最多有一瓶有毒,现在有四只
老鼠,喝了有毒的水之后,第二天就会死。如何在第二天就可以判断出哪个瓶子有毒。
解答:
四只老鼠,用二进制可以给瓶子编码0001 - 1111
;
具体操作:
这里我们将水瓶依次编号为1 - 15
, 老鼠依次编号为1 - 4
;每只老鼠分别喝下对应二进制位为1的水,最后根据老鼠的死亡情况,可以定位到哪一瓶水有毒。
比如说老鼠3
和老鼠4
都死了,就证明是第3瓶
水有毒。
二.
六个海盗抢到共计100个宝石,现在由第一个海盗开始轮流提出分赃计划,只要同意计划的人不超过一半,提出计划的海盗会被处死,然后下个人继续提出计划。如果海盗无法获得认可的最大利益,那么一定会投反对。请问第一个海盗如何提出分赃计划,保证自己的利益最大化并且不死?
解:逆向推导题目:以最小的支出争取可以争取的人。
2人: 【0 - 100】
3人: 【99 - 1 - 0】
4人: 【97 - 0 - 2 - 1】
5人: 【97 - 0 - 1 - 0 - 2】
6人:【96 - 0 - 1 - 2 - 1 - 0】
当只剩下
2个
海盗,海盗1
和海盗2
,由海盗1
来提出分赃计划,海盗1
只能是自己得0个金币
,海盗2
分得100金币
,这样才能保证自己不会被处死。当只剩下
3个
海盗,海盗1
、海盗2
、海盗3
,由海盗1
来提出分赃计划,海盗1
给出的分赃计划是海盗1
为99
金币,海盗2
位1金币
,海盗3
为0金币
,这个计划海盗1
和海盗2
肯定同意,超过一半,海盗2
之所以会同意是因为当只剩下海盗2
和海盗3
的时候,海盗2
来提出分赃计划,海盗2
一个金币都没有,所以海盗2
会同意这个计划。当只剩下
4个
海盗,海盗1、海盗2、海盗3、海盗4
,由海盗1
来提出分赃计划,海盗1
提出的分赃计划是海盗1
为97
金币,海盗2
为0
金币,海盗3
为2
金币,海盗4
为1金币
,之所以这么分配是依据只有3个海盗
的情况来判断,对于海盗2
来说,如果只有3个海盗
,他可以分得99个金币
,所以干脆给他0个金币
;海盗3
,如果只有3个海盗
可以分得1个金币
,所以给他2个金币
,海盗2
肯定同意,海盗4
,如果只有3个海盗
可以分得0个金币
,所以给他1个金币
,他也会同意。这样就会超过一半的人同意这个方案。当只剩下
5个
海盗,海盗1提出的分赃计划是海盗1
为97
个金币,海盗2
为0个
金币,海盗3
为1个金币
,海盗4
为0个金币
,海盗5
为2个金币
,这样就能保证超过一半的人同意这个计划。当只剩下
6个
海盗时,海盗1
提出的分赃计划是海盗1
为96个
金币,海盗2
为0个
金币,海盗3
为1个金币
,海盗4
为2个金币
,海盗5
为1个金币
,这样就能保证超过一半的人同意这个计划。
三.
有
100
个人抢红包,每6
个人可以成组领取共计3
元红包,每个人限领3
次,请问100
个人最多可以领取多少钱?
解:
首先100
个人中找出4
个人,称作A4
,其余96人
组成16
组领取红包。接着从96
个人中找出4
个,称作B4
,A4
和另外92
个人组成16
组领取红包。再从剩下92
个人里面找出4人
称作C4
,A4+B4+88
人组成16
组领取。最后剩下领取了两次的A4、B4、C4
一起组成两组,领取红包,每个人都领取三次,共计领取150
元
四.
假设有
10GB
的订单数据,我们希望按照订单金额(假设金额都是正整数
)进行排序,但是内存有限只有100M
,没办法一次性将10GB
的数据都加载到内存中,请问要怎么进行排序。
解:
先将
10GB
的数据,分成100
份,每份100M
,然后分段加载进内存,遍历统计订单金额所在范围,假设统计范围为0 - 10万
之间,我们将所有的订单依据订单金额划分为100
个桶,第一个桶的金额为0 - 1000
元, 第二个桶是1001 - 2000
元,以此类推,每个桶对应一个存储文件,并且按照金额范围大小顺序编号命名(00, 01, 02, ... 99)
;然后再次分段遍历
10GB
的订单数据,将依据订单金额,将订单放入对应的桶中,然后存储到相应的磁盘上,如果订单金额分布比较均匀,那每个桶最终的订单大小差不多是100M
左右,但也可能出现相差较大的现象,那就将桶中订单数据大小超过100M
的继续在该桶金额范围内继续划分,直到每个桶的订单数据大小,小于100M
。然后依次加载每个桶的订单数据,依据订单金额,对数据从小到大进行排序。
五.
在一个文件中有
10G
个整数,乱序排列,要求找出中位数
。内存限制为2G
。只写出思路即可(内存限制为2G
的意思就是,可以使用2G
的空间来运行程序,而不考虑这台机器上的其他软件的占用内存)。
解:
思路: 一个整数占4
个字节,每个字节是8
位,将整形的每1
位作为一个关键字,如果最高位值越大,整数越大,如果最高位相同再比较次高位。整个比较过程类似于字符串的字典排序。
将
10G
整数分成5
次,每次2G
读入内存,然后遍历读入内存的数据,对每个数据利用位运算取出最高的8
位(24 - 31
),这8bi
t最多可以表示255
个桶,因此依据最高8bit
的值,将整数放入对应的桶中。最后把每个桶写入磁盘中,同时在统计每个桶中的整数数量,并存储。依据内存中统计的每个桶的整数数量,计算中位数在哪个桶中,然后对这个桶进行排序,取出中位数的值。
如果中位数所处的桶的大小超过2G,那么就对这个桶里面的数据依据
次高8位
继续进行划分(16- 23
),并统计各个桶中的数量,然后依据之前算成来的桶的数量进行计算,算成中位数处于哪个桶,并对该桶进行排序,取出中位数。
六.
假设我们有 10 万条 URL 访问日志,如何按照访问次数给 URL 排序?
解:
遍历
10
万条数据,以URL
作为Key
,访问次数作为Value
,存入散列表,同时记录下访问次数的最大值k
,时间复杂度O(N)
;如果
K
不是很大,可以使用桶排序
,时间复杂度是O(N)
,如果K
非常大,就使用快速排序,时间复杂度为O(nlogn)
;
七.
有两个字符串数组,每个数组大约有
10
万条字符串,如何快速找出两个数组中相同的字符串。
- 以第一个字符串数组构建
HashSet
,key
为字符串,再遍历第二个字符串数组,以字符串为key
在HashSet
查找,如果包含就说明存在与该字符相同的字符串,添加到相同列表里面。
八.
假设猎聘网有
10
万名猎头,每个猎头都可以通过做任务(比如发布职位)来积累积分,然后通过积分来下载简历。假设你是猎聘网的一名工程师,如何在内存中存储这10
万个猎头ID
和积分信息,让它支持如下操作:
根据猎头的
ID
快速查找、删除、更新这个猎头的积分信息。查找积分在某个区间的猎头
ID
列表;查找按照积分从小到大排名在
第x位
到第y位
之间的猎头ID列表。
解:
以
猎头ID
构建一个散列表
,以积分排序
构建一个跳表
ID
在散列表中所以可以O(1)
查找到这个猎头积分
以跳表
存储,跳表
支持区间查询
九.
区块链使用的是哪种哈希算法吗?是为了解决什么问题而使用的呢?
解:
区块链
是一块块区块组成的,每个区块分为两部分:区块头
和区块体
。区块头
保存着自己的区块体
和上一个区块头
的哈希值
因为这种
链式
关系和哈希值
的唯一性,只要区块链上任意一个区块被修改过,后面所有区块保存的哈希值就不对了。区块链使用的是
SHA256
哈希算法,计算哈希值非常耗时,如果要篡改一个区块,就必须重新计算后面所有区块的哈希值,短时间几乎不可能做到。