题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

分析:首先考虑这个问题的一个简单版本:一个数组里除了一个数字之外,其他的数字都出现了两次。请写程序找出这个只出现一次的数字。这个题目的突破口在哪里?题目为什么要强调有一个数字出现一次,其他的出现两次?想到了异或运算的性质:任何一个数字异或它自己都等于0。也就是说,如果从头到尾依次异或数组中的每一个数字,那么最终的结果刚好是那个只出现一次的数字,因为那些出现两次的数字全部在异或中抵消掉了。

有了上面简单问题的解决方案之后,回到原始的问题。如果能够把原数组分为两个子数组,在每个子数组中,包含一个只出现一次的数字,而其他数字都出现两次。如果能够这样拆分原数组,按照前面的办法就是分别求出这两个只出现一次的数字了。

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

现在已经把原数组分成了两个子数组,每个子数组都包含一个只出现一次的数字,而其他数字都出现了两次。因此到此为止,所有的问题都已经解决。

#include <iostream>
using namespace std;  // Find the index of first bit which is 1 in num (assuming not 0)
unsigned int FindFirstBitIs1(int num)
{  int indexBit = 0;  while (((num & 1) == 0) && (indexBit < 32))  {  num = num >> 1; ++ indexBit;  }  return indexBit;
}  // Is the indexBit bit of num 1?
bool IsBit1(int num, unsigned int indexBit)
{  num = num >> indexBit;  return (num & 1);
}  // Find two numbers which only appear once in an array
// Input: data - an array contains two number appearing exactly once,
void FindNumsAppearOnce(int data[], int length, int &num1, int &num2)
{  if (length < 2)    return;  // get num1 ^ num2   int resultExclusiveOR = 0;  for (int i = 0; i < length; ++ i)  resultExclusiveOR ^= data[i];  // get index of the first bit, which is 1 in resultExclusiveOR   unsigned int indexOf1 = FindFirstBitIs1(resultExclusiveOR);   num1 = num2 = 0;  for (int j = 0; j < length; ++ j)  {  // divide the numbers in data into two groups,   // the indexOf1 bit of numbers in the first group is 1,   // while in the second group is 0   if(IsBit1(data[j], indexOf1))  num1 ^= data[j];  else  num2 ^= data[j];  }
}  int main()
{  int a[8] = {2,3,6,8,3,2,7,7};  int x,y;  FindNumsAppearOnce(a,8,x,y);  cout<<x<<"\t"<<y<<endl;  return 0;
}

题目:一个整型数组里有三个数字出现了一次,其他的数字都出现了两次。请写程序找出这3个只出现一次的数字。

分析:思路类似于上题,关键是找出第一个来,然后借助上题结论求另外两个。

假设x y z为只出现一次的数,其他出现偶数次。lowbit为某个数从右往左扫描第一次出现1的位置,则x^y、 x^z、 y^z 这三个值的lowbit有一个规律,其中肯定两个是一样的,另外一个是不一样的。令flips为上述三个值的异或,即flips=lowbit(a^b)^lowbit(a^c)^lowbit(b^c)。因此,可以利用此条件获得某个x(或者y,或者z),循环判断的条件是a[i]^xors的lowbit==flips(其中xors为所有数的异或值)
解释:a[i]^xors即可划分为两组,一组是lowbit与flips不同,一组是lowbit与flips相同。这样就能找到某个x,y,z,找出后,将其与数组最后一个值交换,在利用上题思路,在前面n-1个数中找出剩余两个。

#include <iostream>
using namespace std;int lowbit(int x)
{return x & ~(x - 1);
}void Find2(int seq[], int n, int& a, int& b)
{int i, xors = 0;for(i = 0; i < n; i++)xors ^= seq[i];int diff = lowbit(xors);a = 0,b = 0;for(i = 0; i < n; i++){if(diff & seq[i]) //与运算,表示数组中与异或结果位为1的位数相同a ^= seq[i];elseb ^= seq[i];}
}//三个数两两的异或后lowbit有两个相同,一个不同,可以分为两组
void Find3(int seq[], int n, int& a, int& b, int& c)
{int i, xors = 0;for(i = 0; i < n; i++)xors ^= seq[i];int flips = 0;for(i = 0; i < n; i++) //因为出现偶数次的seq[i]和xors的异或,异或结果不改变flips ^= lowbit(xors ^ seq[i]); //表示的是:flips = lowbit(a^b) ^ lowbit(a^c) ^ lowbit(b^c)//三个数两两异或后lowbit有两个相同,一个不同,可以分为两组//所以flips的值为:lowbit(a^b) 或 lowbit(a^c) 或 lowbit(b^c)//得到三个数中的一个a = 0;for(i = 0; i < n; i++){if(lowbit(seq[i] ^ xors) == flips)     //找出三个数两两异或后的lowbit与另外两个lowbit不同的那个数a ^= seq[i];}//找出后,与数组中最后一个值交换,利用Find2,找出剩余的两个for(i = 0; i < n; i++){if(a == seq[i]){int temp = seq[i];seq[i] = seq[n - 1];seq[n - 1] = temp;}}//利用Find2,找出剩余的两个Find2(seq, n - 1, b, c);
}
//假设数组中只有2(010)、3(011)、5(101)三个数,2与3异或后为001,2与5异或后为111,3与5异或后为110,
//则flips的值为lowbit(001)^lowbit(111)^lowbit(110)= 2 ,当异或结果xors与第一个数2异或的时候,得到的就是3与5异或的结果110,其lowbit值等于flips,所以最先找出来的是三个数中的第一个数:2int main(void)
{int seq[]={ 2,3,3,2,4,6,4,10,9,8,8 };int a,b,c;Find3(seq, 11, a, b, c);cout<<a<<endl;cout<<b<<endl;cout<<c<<endl;return 0;
}

寻找数组中只出现一次的数相关推荐

  1. 找出数组中只出现一次的数

    case1 一个整形数组中除了一个数字之外,其他数字都出现了两次,请找出这个数.要求时间复杂度O(n),空间复杂度O(1). 思路: 关键词:一次,两次. 出现两次会带来什么效果?联想到异或,一个数与 ...

  2. 无序数组求第k大的数 python_【python刷题】寻找数组中第K大/小的数

    使用堆 import heapq def findKthLargest(nums, k): stack = [] for num in nums: heapq.heappush(stack, num) ...

  3. 数组中只出现一次的数字

    一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. 数字都出现两次,则异或肯定为0. 考虑下这个题目的简化版--数组中除一个数字只出现1次外,其它数字都成对出 ...

  4. 整数:求数组Nums中只出现一次的数

    文章目录 题目 考察知识点 位运算 解题思路 总结 扩展:举一反三 解答思路 题目 数组Nums, 只有一个数只出现一次,其余的数都会出现3次. 例如: 输入: Nums[2,2,3,2]. 输出:3 ...

  5. 算法-寻找数组中的重复值,四种解法

    算法-寻找数组中的重复值 寻找数组中的重复值 寻找数组中的重复值 题目来源于:Leetcode-287.本题归类到简单我无法理解-要满足四个条件需要用很特定的解法,面试中要是用到的话很可能是在给自己挖 ...

  6. 【剑指offer-Java版】40数组中只出现一次的数字

    数组中只出现一次的数字:输入一个数组,该数组中有两个数字只出现了一次,其他数字都出现了两次,求出这两个只出现了一次的数字 要求时间复杂度为O(n)空间复杂度为O(1) 考虑一个数组中只有一个数字仅仅出 ...

  7. 编程之美2.10 寻找数组中的最大值和最小值

    这个问题其实很容易解决,就是循环遍历一遍数组,然后找到数组中存在的最大值和最小值就可以了,书中主要讨论的问题是比较次数较小的方法,不过,书中已经证明了,无论用什么方法最少的比较次数也就是循环遍历一遍的 ...

  8. 《剑指offer》-- 第一个只出现一次的字符、数组中只出现一次的数字、字符流中第一个不重复的字符、数组中重复的数字

    一.第一个只出现一次的字符: 1.题目: 在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写 ...

  9. 数组中只出现1次的2个数

    数组中只出现1次的2个数 如题所示: 思路 源代码如下: 如题所示: 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字 可以先考虑如果只有1个数字出现1次,其 ...

最新文章

  1. YARN体系学习笔记
  2. C++在windows下获取本地主机ipv4地址和ipv6地址的代码
  3. 【财经】人人网(校内网) -- 盈利模式
  4. OpenJTAG与JLink的区别比较
  5. Pycharm2019版中打开.md .st文件出现卡死情况怎么办?
  6. r intersect()_30分钟掌握R语言编程基础
  7. mqtt消息队列安装并启用启用认证(客户端密码模式)
  8. windows下工具
  9. 本科毕业查重过程分享与经验
  10. MyBatis【钢镚核恒】
  11. 云计算十字真言及其在小博无线的实践
  12. MATLAB(五) 图像处理--图像分割
  13. pgAdmin4数据库备份还原
  14. 基于springboot的人才求职招聘平台设计与实现
  15. VMVare中Ubuntu报错:Drag and drop is not supported
  16. hdu 4394 Digital Square【标准DFS】
  17. android仿qq分组列表效果
  18. 用TypeScript写界面就是个笑话, 狗屎级别的体验.根本体验不到脚本语言带来的好处.
  19. kali2020之快速搜索文件工具——安装篇
  20. atx860和java_JAVA 版 ATX-Client

热门文章

  1. 正则表达式之IP地址检验
  2. CentOS下安装protobuf
  3. 解决WebStrom、PhpStorm等JetBrains软件最新版的中文打字法问题
  4. 解决LNMP环境下客户端远程连接不上mysql的问题(已经排除防火墙/selinux问题)...
  5. 【FTP】FTP 命令模式下 PASV OR PORT
  6. 一些小标签(上标下标下划线等)
  7. Apache访问日志切割
  8. Sizeof与Strlen的区别与联系
  9. JS去除字符串左右两端的空格
  10. ASP.NET AJAX入门系列(11):在多个UpdatePanle中使用Timer控件