zoukankan      html  css  js  c++  java
  • 编程之美读书笔记之 -寻找出现次数为1的ID的问题

    问题描述:
    在一张表里面保存了N个ID,有N-1个ID是出现了两次的,只有一个ID只出现了一次,现在要你把这个ID找出来。如果是两个呢?
     
    解法一:
    我们先来解决一个的。假如ID的值的范围是1-k,当这个k不大的时候,我们可以直接开一个数组,把表扫一遍,记录下每个ID出现的次数,这样,出现一次的就的出来了,这样做的时间复杂度是O(n),空间复杂度也是O(n)。
    解法二:
    然而,当k很大很大时,这种做法显然就不行了。然后我们提出第二种对这种优化的方法,就是利用哈希,对每个ID哈希一遍,保存在哈希表里,然后,当我在插入的时候发现,这个ID已经出现过的时候,就把这个ID从哈希表里面删除掉,最后剩下只有一个ID,那就是只出现过一次的ID。这样时间复杂度仍然是O(n),其实时间复杂度O(n)已经没有什么可以优化的空间了。关键是空间复杂度能不能优化到O(1)呢?
    解法三:
    优化到O(1),也就是说,只有使用一个变量,这也就意味着,这个变量最后保存的值就是我们要找的ID。我们可以这样描述这个过程:
    ID = f(A[0 : n-1])
    关键就是怎样设计这个f()。
    这里有一个很巧妙的方法。我们知道两个数异或有这样的性质:
    a ^ a = 0
    a ^ 0 = a
    而且异或满足交换律,所以如果ID是这样一个集合,我们对其进行异或遍历:  a1,a1,a2,a2,a3,a3,.....ak,ak.....an,an
    我们令ak是我们要找的那个ID,这个ID列表是没有顺序的,也就是说相同的ID不一定是相邻的,所以假设是这样的:
    ak1 ^ ak2 ^ ak3......akn这个顺序我们是未知的,但利用异或满足交换律这个特点,可以这样:
    ak1 ^ ak2 ^ ak3......akn
    = a1 ^ a1 ^ a2 ^ a2 ^ ak-1 ^ ak+1 ..... ^ an ^ ak
    而a1 ^ a1 = 0,所以前n-1个异或的结果为0,最后剩下
    0 ^ ak = ak
    所以,最后异或的结果就是只出现一个的那个ID。
     
    然后,如果是两个呢?如果两个A和B,ID只出现一次呢?怎样在O(n)时间跟O(1)空间的条件下找到这两个ID呢?
    像上一种方法一样,直接异或遍历,只能得到两个ID异或的结果,不能得到两个ID。
    我们可以顺势就在这两个ID异或的结果上面做文章,假如异或结果为0,说明是两个相等的ID,这里先不做讨论,假如异或的结果不为0,那么结果至少有一位上为1的,这就说明,A跟B至少在这一位上是不相等的,所以,我们可以把这一位所有相同的ID分别放在一类,这样就得到一类是这一位是1的一类,我们称这是X类,另一类的这一位是0的一类,称为Y类,因为其它的n-2的ID是完全相同的,所以,如果一个ID在这一位是1,那么这两个ID一定同时被分在X类中,所以最终的结果是X类中有一个A或者B ID,Y类中有一个A或者B  ID ,但可以肯定的是A跟B一定不在同一类中,所以,我们又可以分别对这两类ID进行异或,又可以得到A和B
     
  • 相关阅读:
    pinyin4j 实现 中文和拼音之间转化
    关于Exceptionless日志收集框架如何关闭磁盘缓存
    WPF桌面程序在请求接口时如何防止被常用的抓包软件Fiddler抓包
    Docker可视化容器Portainer
    记我第一次玩Docker
    最火热的极速开发框架Spring Boot
    MySQL开发规范
    5分钟入门AWK
    必须掌握的30种SQL语句优化
    支付接口的幂等性设计
  • 原文地址:https://www.cnblogs.com/xiaxiaosheng/p/4746573.html
Copyright © 2011-2022 走看看