编程之美之找出故障机器

问题:假设一个机器仅仅存储一个标号为ID的记录(ID小于10亿的整数),每个数据保存2个备份,这样就有2个机器存储了同样的数据。

提问1某时间如果得到一个数据文件ID的列表,是否能够快速地找出这个表中仅仅出现一次的ID?

提问2如果已经知道只有一台机器死机(即只有一个备份丢失)呢?如果有2台机器死机(设同一个数据的两个备份不会同时丢失)?

解提问1转换为有很多ID,其中只有一个ID出现次数小于2,其他正常ID出现次数等于2,如何找到这个次数为1ID

解法一   遍历计数 

思路:遍历ID列表,用一个数组记下每个ID出现的次数,遍历完毕后出现次数小于2的就是所需结果。

时间复杂度为O(N),空间复杂度为O(N)

缺点:当ID数量多达即G时,空间复杂度效率明显出现问题,能否减小空间复杂度,对于出现2次的ID可以删除,因为已经不符合条件。解法二就是这个思路。

解法二 遍历列表对于出现次数为2 ID不存储

利用hash表记下每一个ID的出现次数,遇见一个IDhash表中增加一个元素,如果ID的出现次数为2,则将其从hash表中删除,最后剩下的就是所需ID

算法空间复杂度为最好为O1),最差仍为O(N)

解法三  异或运算

试图进一步降低空间复杂度,若要继续降低空间复杂度就有摒弃遍历列表计数这种方法。将列表中的ID进行异或由于问题一中除所求ID外都出现2次,故对列表中的ID进行异或后得到的结果就是出现次数为1ID

缺点:上述针对只有一个ID出现次数为1的情况,出现多次则不可行。

解提问2  2ID(设为A,B )仅仅出现一次,解法一二适用,但解法三所有ID的异或值为A⊕B,无法确定AB的值。

书中分情况讨论

② A=B时,则A=B=(所有ID之和—所有正常工作机器ID之和)/2

②若A!=BA⊕B不为0,但异或值的某一位为1,那么AB的相同位上也为1,将ID列表根据该位分为2组,一组该位为1,另一组该位为0,每一类中分别含有AB,使用两个变量遍历列表时分别计算这两类ID的异或值,即可得到AB的值(因为对应组别中仅仅A或者B出现一次,其他ID 都出现2次)。

解法四  利用不变量

针对提问一   将所有ID求和与死机后的ID列表和相减即为死机机器所存ID

针对第二问   2ID不同的情形

(1) 计算未丢失之前所有ID和,计算丢失ID之后的和

(2) 将上述2和相减得到A+B=P

(3) 利用丢失前后的ID平方和之差与(2)联立求解AB

书中第二个方程利用丢失前后ID的乘积求得A*B的值,也提出乘积会导致溢出建议采用平方和。

扩展问题   3个备份的时候,可有和,平方和,三者乘积得到3个方程,N个时会没有足够的方程无法求解。

扑克牌问题 未抽取牌前的和减去抽取牌后的和即可。全部异或也可。

 

哈希表  归并排序,快速排序

 

 

 

    原文作者:梦之未来
    原文地址: https://blog.csdn.net/asd199086/article/details/51355810
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞