问题描述:
在一张表里面保存了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. Hibernate考试选择题解析

    1.在Hibernate中,以下关于主键生成器说法错误的是(AC). A.increment可以用于类型为long.short或byte的主键(byte类型不可以) B.identity用于如SQL ...

  2. angular的跨域(angular百度下拉提示模拟)和angular选项卡

    1.angular中$http的服务: $http.get(url,{params:{参数}}).success().error(); $http.post(url,{params:{参数}}).su ...

  3. JSP九大内置组件

    request:用户端请求,此请求会包含来自get/post请求的参数 response:网页传回用户端的回应 pagecontext:网页上下文,也就是网页的属性 session:与请求有关的会话期 ...

  4. ajax返回值中有回车换行、空格的解决方法分享

    最近在写一个页面,用jquery ajax来实现判断,刚写好测试完全没有问题,过了两天发现出现问题,判断不成了.后来发现所有alert出来的返回值前面都会加若干换行和空格.(至今不明白,同一台电脑,同 ...

  5. 20145315&20145307《信息安全系统设计基础》实验五

    20145315&20145307<信息安全系统设计基础>实验五 北京电子科技学院(BESTI) 实 验 报 告 课程:信息安全系统设计基础 班级:1453 1452 姓名:陈俊达 ...

  6. 线段树 HDU 3397

    5种操作 具体看代码 #include<iostream> #include<stdio.h> #include<string.h> #include<alg ...

  7. 关于GeoWebCache的部署说明

    最近因为工作需要学习了GeoWebCache,有了一些实战经验跟大家分享一下. 废话不多说,直接上问题! 1.切片的缓存问题 当地图服务(这里默认指WMS)的数据更新时,GeoWebCache的切片如 ...

  8. miniui后台无法接收到input传值

    出错原因:在miniui中,此处应写成<input textName="current_unit",在php中才可以使用$_POST['current_unit']获取到值, ...

  9. TP-LINK WR941 DD-WRT刷回OpenWRT及OpenWRT刷回原厂固件

    1.DD-Wrt 刷回 OpenWrt A.从官网下载固件: root@TL-DDWRT:/tmp# wget http://downloads.openwrt.org/barrier_breaker ...

  10. Linux(Centos6.5)用户名密码

    用户列表文件:/etc/passwd用户组列表文件:/etc/group 查看系统中有哪些用户:cut -d : -f 1 /etc/passwd查看可以登录系统的用户:cat /etc/passwd ...