剑指offer面试题40:数组中只出现一次的数字

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

一看到这个题想到了很多“可能”的解法,很飘散的思绪,比如什么哈希啊,什么加A再减去A,剩下的就是单独的了啊,都是写没啥用的解法。

后面看到了书上的解法,觉得很巧妙,于是贴了上来,顺便标明了自己当时不是很清楚的理解。

 书上说这道题很难,我觉得算法这种东西,本质上并没有难一说,而是主张一个“巧妙”,九拐十八弯。

 从易入难,举一反三是算法学习中必不可少的一种经历。

闲话少说,言归正传,首先这个题目是要求我们找出数组中的两个分别出现了一次的数字,而且时间复杂度要求O(n),如果说我们想靠找到数组中的一个A再在后面找到另一个A,这样的话,时间复杂度完全不符合要求,相应的时间复杂度为O(n^2),太。。。。慢了。。

那么怎样才能解决这个问题呢?

根据书上的提示,我们先来考虑一个比较 简单的场景,即数组中只有一个单独的不成对的数,我们可以通过连续对数组中的元素求异或(“^”操作),因为A和A的异或结果是为零的,根据这个思想,我们可以把异或的结果保存到一个result变量里,到最后这个变量的结果就是我们所求的那个单独的数。(当时困扰楼主了一会儿,让lz感觉到莫名其妙的是书上的”依次异或“这句话,楼主心想,依次异或,难不成还是依次便利数组中的元素,求异或?这样的复杂度还是O(n^2),太诡异了,现在才发现自己当时的想法是错误的,曲解了作者的想法,希望有这么理解的同学不要再这么想了~)

 

接下来考虑数组中拥有两个独立数据的情况,对这个数组中的元素同样进行上述的异或操作,得到的最终结果是两个不同的数的异或结果,由于两个数不相同,那么这个结果中肯定不为零,也就是存在1的位数,我们可以根据此结果把这个数组分成两个子数组,从低到高位,第一个1出现的位数为1的数和这位为0的数为两个数组,那么肯定的是,这两个单独的数分别被分到了两个子数组里,那么就好办了,对这两个子数组的元素分别进行异或操作,得到的就是这两个单独的数。

 

根据此思路完成的代码如下:

 

 1 #include<iostream>
 2  using  namespace std;
 3 
 4  void find_two_aloneC( int a[], int length)
 5 {
 6      int i,j= 1,Xor= 0,Xor_0= 0,Xor_1= 0;
 7     
 8      for(i = 0;i<length;i++)
 9         Xor = Xor^a[i];
10      while(((Xor &  1) ==  0))
11     {
12         Xor = (Xor >>  1);
13         j = j <<  1;
14     }
15      for(i =  0;i<length;i++)
16     {
17          if((a[i] & j) ==  0)
18         {
19             Xor_0 = Xor_0^a[i];
20         }
21          else  if((a[i] & j )!= 0)
22         {
23             Xor_1 = Xor_1^a[i];
24         }
25     }
26     cout << Xor_0 << endl;
27     cout << Xor_1 << endl;
28 }
29  int main()
30 {
31      int a[] = { 2, 3, 4, 5, 3, 3, 3, 5, 2, 5};
32     find_two_aloneC(a, 10);
33     system( " pause ");
34     
35      return  0;
36 }

 

转载于:https://www.cnblogs.com/xiawen/archive/2013/04/16/3023832.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值