问题描述:
在一张表里面保存了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
 

编程之美读书笔记之 -寻找出现次数为1的ID的问题的更多相关文章

  1. 编程之美读书笔记1.1——让CPU占用率曲线听你的指挥

    http://blog.csdn.net/pipisorry/article/details/36189155 <strong><span style="font-size ...

  2. 《Linux/Unix系统编程手册》读书笔记 目录

    <Linux/Unix系统编程手册>读书笔记1  (创建于4月3日,最后更新4月7日) <Linux/Unix系统编程手册>读书笔记2  (创建于4月9日,最后更新4月10日) ...

  3. 《Linux/Unix系统编程手册》读书笔记9(文件属性)

    <Linux/Unix系统编程手册>读书笔记 目录 在Linux里,万物皆文件.所以文件系统在Linux系统占有重要的地位.本文主要介绍的是文件的属性,只是稍微提及一下文件系统,日后如果有 ...

  4. 《Linux/Unix系统编程手册》读书笔记8 (文件I/O缓冲)

    <Linux/Unix系统编程手册>读书笔记 目录 第13章 这章主要将了关于文件I/O的缓冲. 系统I/O调用(即内核)和C语言标准库I/O函数(即stdio函数)在对磁盘进行操作的时候 ...

  5. 《Linux/Unix系统编程手册》读书笔记7 (/proc文件的简介和运用)

    <Linux/Unix系统编程手册>读书笔记 目录 第11章 这章主要讲了关于Linux和UNIX的系统资源的限制. 关于限制都存在一个最小值,这些最小值为<limits.h> ...

  6. 《Linux/Unix系统编程手册》读书笔记6

    <Linux/Unix系统编程手册>读书笔记 目录 第9章 这章主要讲了一堆关于进程的ID.实际用户(组)ID.有效用户(组)ID.保存设置用户(组)ID.文件系统用户(组)ID.和辅助组 ...

  7. 《Linux/Unix系统编程手册》读书笔记5

    <Linux/Unix系统编程手册>读书笔记 目录 第8章 本章讲了用户和组,还有记录用户的密码文件/etc/passwd,shadow密码文件/etc/shadow还有组文件/etc/g ...

  8. 《Linux/Unix系统编程手册》读书笔记4

    <Linux/Unix系统编程手册>读书笔记 目录 第7章: 内存分配 通过增加堆的大小分配内存,通过提升program break位置的高度来分配内存. 基本学过C语言的都用过mallo ...

  9. 《Linux/Unix系统编程手册》读书笔记3

    <Linux/Unix系统编程手册>读书笔记 目录 第6章 这章讲进程.虚拟内存和环境变量等. 进程是一个可执行程序的实例.一个程序可以创建很多进程. 进程是由内核定义的抽象实体,内核为此 ...

随机推荐

  1. Android与Struts2简单json通信

    具体要求是: 服务器端得到客户端传递来的数据,并返回给客户端一条json格式的字符串 闲话不多说,直接上代码 首先是服务器端代码:建立一个web工程,导入struts2和json的jar包,并在web ...

  2. 杂项之pymysql连接池

    杂项之pymysql连接池 本节内容 本文的诞生 连接池及单例模式 多线程提升 协程提升 后记 1.本文的诞生 由于前几天接触了pymysql,在测试数据过程中,使用普通的pymysql插入100W条 ...

  3. http协议进阶(二)URL与资源

    一.URL的语法  URL是互联网资源的标准化名称 URL提供了一种定位互联网上任意资源的手段,但这些资源要通过不同方案(协议:比如http.ftp.smtp)来访问,因此URL语法会略有差异 大部分 ...

  4. Nginx负载均衡实践之一:基本实现

    由于现在的网站架构越来越大,基于互联网的用户也是日渐增长,所以传统的单机版服务器已经渐渐不能适应时代发展的需要.最近在和其他企业接触的过程中,发现对于互联网的经验尤为看重,所谓的互联网经验,其实就是指 ...

  5. [网络安全] [视频分享]KaLi Linux基础培训2016 最新的哦【福吧资源网】

    最新的教程同时针对kali linux2016最新版本的多个问题解决办法还有一些实例利用. 下载地址:http://www.fu83.cn/thread-310-1-1.html

  6. 国内可用maven repository 配置

    国内可用maven repository 配置 发表于2016/1/4 23:08:04  10235人阅读 分类: maven 鉴于一些原因,从maven中央仓库download依赖包时,被各种折磨 ...

  7. 学习SAP HANA SQL

      学习SAP HANA SQL 语句(创建 EMP,DEPT,BONUS 和 SALGRADE测试表)--像学Oracle一样学习SAP HANA 标签: sap测试oraclesqltableda ...

  8. AppBox升级进行时 - 拥抱Entity Framework的Code First开发模式

    AppBox 是基于 FineUI 的通用权限管理框架,包括用户管理.职称管理.部门管理.角色管理.角色权限管理等模块. 从Subsonic到Entity Framework Subsonic最早发布 ...

  9. npm+node+cordova+ionic 版本匹配

    npm 2.15.8 node 4.4.7 cordova 6.1.0 ionic 1.7.16

  10. mysql数据库表结构导出

    mysql数据库表结构导出 命令行下具体用法如下: mysqldump -u用戶名 -p密码 -d 数据库名 表名 > 脚本名; 导出整个数据库结构和数据 mysqldump -h localh ...