题目描述

一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。

题目地址

https://www.nowcoder.com/practice/e02fdb54d7524710a7d664d082bb7811?tpId=13&tqId=11193&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

思路

思路1:考虑用哈希表的方法,但是空间复杂度不是O(1)。应该怎么做才能即满足时间复杂度是O(n)又满足空间复杂度是O(1)的要求呢?

思路2:

我们可以想一想“异或”运算的一个性质,我们直接举例说明。

举例:{2,4,3,6,3,2,5,5}

这个数组中只出现一次的两个数分别是4和6。怎么找到这个两个数字呢?

我们先不看找到俩个的情况,先看这样一个问题,如何在一个数组中找到一个只出现一次的数字呢?比如数组:{4,5,5},唯一一个只出现一次的数字是4。

我们知道异或的一个性质是:任何一个数字异或它自己都等于0。也就是说,如果我们从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现一次的数字。比如数组{4,5,5},我们先用数组中的第一个元素4(二进制形式:0100)和数组中的第二个元素5(二进制形式:0101)进行异或操作,0100和0101异或得到0001,用这个得到的元素与数组中的三个元素5(二进制形式:0101)进行异或操作,0001和0101异或得到0100,正好是结果数字4。这是因为数组中相同的元素异或是为0的,因此就只剩下那个不成对的孤苦伶仃元素。

现在好了,我们已经知道了如何找到一个数组中找到一个只出现一次的数字,那么我们如何在一个数组中找到两个只出现一次的数字呢?如果,我们可以将原始数组分成两个子数组,使得每个子数组包含一个只出现一次的数字,而其他数字都成对出现。这样,我们就可以用上述方法找到那个孤苦伶仃的元素。

我们还是从头到尾一次异或数组中的每一个数字,那么最终得到的结果就是两个只出现一次的数组的异或结果。因为其他数字都出现了两次,在异或中全部抵消了。由于两个数字肯定不一样,那么异或的结果肯定不为0,也就是说这个结果数组的二进制表示至少有一个位为1。我们在结果数组中找到第一个为1的位的位置,记为第n位。现在我们以第n位是不是1为标准把元数组中的数字分成两个子数组,第一个子数组中每个数字的第n位都是1,而第二个子数组中每个数字的第n位都是0。

举例:{2,4,3,6,3,2,5,5}

我们依次对数组中的每个数字做异或运行之后,得到的结果用二进制表示是0010。异或得到结果中的倒数第二位是1,于是我们根据数字的倒数第二位是不是1分为两个子数组。第一个子数组{2,3,6,3,2}中所有数字的倒数第二位都是1,而第二个子数组{4,5,5}中所有数字的倒数第二位都是0。接下来只要分别两个子数组求异或,就能找到第一个子数组中只出现一次的数字是6,而第二个子数组中只出现一次的数字是4。

Python

# -*- coding:utf-8 -*-
class Solution:
# 返回[a,b] 其中ab是出现一次的两个数字
def FindNumsAppearOnce(self, array):
# write code here
if len(array)<=1:
return []
# 思路1:hash
# dict = {}
# for x in array:
# if x not in dict:
# dict[x] = 1
# else:
# dict[x] = False
# res = []
# for key, val in dict.items():
# if val == 1:
# res.append(key)
# return res
# 思路2:位运算
Or = 0
for x in array:
Or ^= x
indexOf1 = self.findFirstBitIs1(Or)
num1, num2 = 0, 0
for i in array:
if self.BitIs1(i,indexOf1):
num1 ^= i
else:
num2 ^= i
return num1, num2 def findFirstBitIs1(self,num):
indexOf1 = 0
while num&1==0 and indexOf1 <= 32:
indexOf1 += 1
num = num >>1
return indexOf1
def BitIs1(self,num,indexOf1):
num = num >> indexOf1
return num &1 if __name__ == '__main__':
result = Solution().FindNumsAppearOnce([1,2,2,3,3,3,3,4,5,5])
print(result)

最新文章

  1. swift实现水仙花数
  2. Swift与OC混编
  3. HTTP笔记整理(2)
  4. PHP+MYSQL+AJAX实现每日签到功能
  5. &lt;构建之法&gt; 第四章 结对 读后感
  6. IOS View传统的价值观之间
  7. php5.3.*编译出现make: *** [ext/gd/libgd/gd_compat.lo] Error 1 解决方法
  8. CentOS 7.3.1611系统安装配置图解教程
  9. 在SD/MMC卡上实现hive (Implement WinCE HIVE&amp;ROM system on NAND or SD system )
  10. easyui 菜单树搜索
  11. Oracle11g 体系结构
  12. Stm32串口通信(USART)
  13. SpringBoot使用JdbcTemplate
  14. 2 爬虫 requests模块
  15. 单元测试使用spring注解获取bean
  16. flume 整合kafka
  17. 异步编程 In .NET(转载)
  18. webdriver定位页面元素时使用set_page_load_time()和JavaScript停止页面加载
  19. DDR2基础
  20. 【转】ArcGIS Server10.1安装常见问题及解决方案

热门文章

  1. Shell 变量知识
  2. Java IO流及应用(一)
  3. linux PWM蜂鸣器移植以及驱动程序分析【转】
  4. 牛客练习赛43C Tachibana Kanade Loves Review
  5. 拦截导弹nlogn解法
  6. 【Entity Framework】Revert the database to specified migration.
  7. React项目中实现右键自定义菜单
  8. Unity --- OnValidate 和 ExecuteInEditMode
  9. 搭建openstf平台的那些事
  10. iOS分类底层实现原理小记