题目描述:
每个机器都有一个标号Id,每个id数据保存两个备份,如果一台机器死机,就会丢失一个备份,如果得到一个数据文件Id的列表,是否能够快速找到这个仅出现一次的Id?
分析:
其实就是海量数据中有一个数据是只出现一次的,其他都是出现两次,找到那个出现一次的数据。
解法一:
这种记录出现次数的问题,最先想到的当然就是伴随数组,遍历列表,数组元素为数据出现次数,数组下标可以是标号id,那个次数为1的Id就是我们要找的结果,时间复杂度为O(N),空间复杂度为O(N)。但是面对海量数据,这个空间复杂度也是够呛。
解法二:
能不能节省数据存储空间呢?这个题的特点就是我们要找的是只出现一次的,如果已经出现了两次,那肯定不是我们要找的,于是,如果次数为2,我们就可以直接丢弃了。使用哈希表,遇到一个元素加入到表中,次数加一,如果次数为2,就删除对应的Id,最后剩下的id就是我们要找的,空间复杂度最好的情况下为O(1),不过最坏的也是O(N)
解法三:
我们发现相同数据出现的是偶数次,最后只剩下一个奇数次的数据,可以考虑使用位运算中的异或(^)。注意异或运算满足交换律和结合律,其他出现两次的Id异或完都是0。我们可以遍历列表,然后依次加入异或运算,最后剩下的就是出现一次的id。
时间复杂度为O(N),空间复杂度为O(1)。
如果是两台机器死机呢?我们能否找到故障机器?
分析:
就是有两个Id只出现了一次,设为A和B。如果使用异或方案,最后剩下的就是A^B,如果A和B相同,就是一台机器的两个备份都丢失了,那么最后A^B为0。如果A和B不相同,则A ^B 不为0,我们可以找到A^B中某一位为1的位,则A和B中只用其中一个对应位上为1,我们可以以此位为判断依据。将Id分为两类,一类此位为1,一类为0,然后分别使用异或的方法,每一类中可以得到一个结果,分别为A和B。
再讨论A和B相同的问题,我们可以保存所有的id的求和,然后再计算剩下的id之和,然后将原来的总和减去当前的id和,得到的是死机机器id的和 A+ B,如果相等,直接(A+B)/2,得到死机的Id 号。