zoukankan      html  css  js  c++  java
  • 算法题008 快速找出故障机器

    快速找出故障机器

     

    题目描述

      关心数据挖掘和搜索引擎的程序员都知道,我们需要很多的计算机来存储和处理海量数据。

      然而,计算机难免出现硬件故障而导致网络联系失败或死机。为了保证搜索引擎的服务质量,我们需要保证每份数据都有多个备份。

      简单起见,假设每个机器存储一个标号为ID的记录(ID是小于十亿的整数),假设每份数据都保存两个备份,这样就有两个机器储存了同样的数据。

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

      2.如果已经知道只有一台机器死机(也就是说只有一个备份丢失)呢?如果有两台机器死机呢(假设同一个数据的两个备份不会同时丢失)?

     

    我的解法

      这个题目肯定要考虑大量数据的处理,即需要重点考虑效率问题。

      首先,ID是小于十亿的整数,这说明用一个long型(4个字节)可以表示ID,不会超出表示范围,所以这点不用担心。

      根据题目特点,得到ID列表后,可以考虑一种像是玩扑克牌游戏的做法,找一个数组来盛放遍历的数(想象成摸牌),找到成对的就丢弃(或者你也可以把这个配对过程想象成连连看)。

      最后将所有数字遍历完之后还留下的就是单独的ID。

      这样时间复杂度是O(n * n),因为需要摸n张牌,并且每摸一张牌都需要和手中的牌进行查询配对。

      下面是书中的解法,看完之后才知道我的解法真是弱爆了,为什么没想到哈希表呢。

    解法一

      直接遍历列表,利用一个数组记录下每个ID出现的次数,遍历完毕之后,出现次数小于2的ID就是我们想要的结果。

      假设有N个ID,且ID的取值在0~N-1之间,这个解法占用的时间复杂度为O(N),空间复杂度为O(N)。

      时间复杂度已经相当理想,但是空间复杂度不够理想,如果ID的数量多达几个G甚至几十G,这样的空间复杂度在实际的运算中就会带来效率问题。

     

    解法二

      考虑到大部分ID的出现次数都等于2,这些ID的信息并不是必要的,所以不必存储。

      因此,可以把解法一数组中等于2的元素清空,然后用来存储下一个机器ID的出现次数,这样就可以减少需要的空间。

      具体方法如下:遍历列表,利用哈希表记下每个ID出现的次数,每次遇见一个新的ID,就向哈希表中增加一个元素;如果这个ID出现的次数为2,那么就从哈希表中删除这个元素,最后剩下的ID就是我们想要的结果。

      这个算法的空间复杂度在最好情况下可以达到O(1),在最坏的情况下仍然是O(N)。

     

    解法三

      对于第一问,假设列表中仅有一个ID出现了一次,那么可以考虑用异或关系来帮忙找到结果。

      因为异或运算的定义是相同为假相异为真,异或运算满足交换律和结合律。

      所以,所有ID的异或值就等于这个仅出现一次的ID。(两两相同的都得到0,0和任何值异或等于原来的任何值)

      这种情况下,时间复杂度为O(N),空间复杂度为O(1)。

     

      对于第二问,由于有两个ID仅出现了一次,设它们为A和B,那么所有ID异或的结果是A异或B,但还是无法确定A和B的值。

      可以进行分类讨论:

      (1)A == B

      这时A异或B等于零,丢失的是同一份数据的两个拷贝,可以通过求和的方法求得A和B,即,所有ID值的和减去所有正常的ID之和,除以2得到A和B。

      (2)A !=B

      这时A异或B不等于零,那么这个异或值的二进制位中某一位为1,此时A和B中有且仅有一个数的相同位上也为1。

      我们就把所有的ID分成两类,一类在这位上为1,另一类在这位上为0。A和B分别位于这两类中。

      我们分别计算这两类的异或和,即可得到A和B的值。(太巧妙了!)

     

    解法四

      对于第一问,缺失一个ID:

      预先计算并保存好所有ID的求和(“不变量”),顺序列举当前所有剩下的ID,对它们求和,然后用所有ID的求和减去当前剩下所有ID的和,结果就是死机的机器的ID值。

      时间复杂度为O(N),空间复杂度为O(1),和解法三一样是计算复杂度最优的算法。

      对于第二问,我们考虑所有的情况,即两个ID可以相同也可以不同。

      用上面的方法可以得到这两个ID的和。我们构造出一个方程: x + y = a; a已知。

      第二个方程有很多构造方法,比如可以用所有ID的乘积计算出另一个不变量,除以所有剩下的ID,结果得到两台死机机器的ID的乘积,即x * y = b

      这样联立两个方程之后,可以解出x和y的值。

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

      第二个方程构造也可以考虑平方和的方法。

     

    参考资料

      《编程之美》1.5节

  • 相关阅读:
    分水岭分割算法(watershed segmentation)的C++实现(法2)
    ubuntu16.04下安装opencv3.3
    分水岭分割算法(watershed segmentation)的C++实现(法1)
    dpkg: 处理归档 /var/cache/apt/archives/swig2.0_2.0.12-1ubuntu4_amd64.deb (--unpack)时出错:
    ubuntu16.04安装pycharm
    ImportError: liblapack.so.3: cannot open shared object file问题
    Linux下使用Opencv打开笔记本摄像头
    目标跟踪算法meanshift优缺点
    Jacobian矩阵和Hessian矩阵
    机器视觉中的目标检测
  • 原文地址:https://www.cnblogs.com/mengdd/p/2962444.html
Copyright © 2011-2022 走看看