100题_34 找出数组中两个只出现一次的数字
个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
可能大家都见识过找出一个只出现一次的数,直接把所有的数异或就可以了,最终的结果就是这个数了。但是如果出现两个这样的数,那又将如何呢?
假如这两个数为a和b,那么将所有的数异或得到的数必定为a^b。由于a和b不相等,那么a^b != 0,也就是说在a^b中必定至少有一位为1,对应位上a与b不一样,根据这一位,我们可以将a和b分开,并将数分成两组。注意,两个相同的数肯定会被分到同一个组。这样,分别对每一组进行取异或,就能求出这两个数了。
代码如下:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 /*
2 * File: main.cpp
3 * Author: ziqiao
4 *
5 * Created on 2011年3月17日, 下午12:05
6 */
7
8 #include <cstdlib>
9 #include <iostream>
10
11 using namespace std;
12
13 int findOutOneOdd(int a[], int n)
14 {
15 int result = a[0];
16 for (int i = 1; i < n; i++)
17 result ^= a[i];
18 return result;
19 }
20
21 void findOutTwoOdds(int a[], int n, int &odd1, int &odd2)
22 {
23 int x = findOutOneOdd(a, n);
24 int i;
25 for (i = 1; i != 0 ; i <<= 1)
26 {
27 if (x & i != 0)
28 break;
29 }
30 if (i == 0)
31 throw "input is illeagle";
32 bool flag1 = false, flag2 = false;
33 for (int j = 0; j < n; j++)
34 {
35 if (a[j] & i != 0)
36 {
37 if (!flag1)
38 {
39 odd1 = a[j];
40 flag1 = true;
41 }
42 else
43 odd1 ^= a[j];
44 }
45 else
46 {
47 if (!flag2)
48 {
49 odd2 = a[j];
50 flag2 = true;
51 }
52 else
53 odd2 ^= a[j];
54 }
55 }
56 }
57
58 /*
59 *
60 */
61 int main(int argc, char** argv)
62 {
63 int a[] = {4, 5, 3, 4, 5, 7, 7, 6, 8, 8};
64 int odd1, odd2;
65 findOutTwoOdds(a, 10, odd1, odd2);
66 cout << odd1 << " " << odd2 << endl;
67 return 0;
68 }
2 * File: main.cpp
3 * Author: ziqiao
4 *
5 * Created on 2011年3月17日, 下午12:05
6 */
7
8 #include <cstdlib>
9 #include <iostream>
10
11 using namespace std;
12
13 int findOutOneOdd(int a[], int n)
14 {
15 int result = a[0];
16 for (int i = 1; i < n; i++)
17 result ^= a[i];
18 return result;
19 }
20
21 void findOutTwoOdds(int a[], int n, int &odd1, int &odd2)
22 {
23 int x = findOutOneOdd(a, n);
24 int i;
25 for (i = 1; i != 0 ; i <<= 1)
26 {
27 if (x & i != 0)
28 break;
29 }
30 if (i == 0)
31 throw "input is illeagle";
32 bool flag1 = false, flag2 = false;
33 for (int j = 0; j < n; j++)
34 {
35 if (a[j] & i != 0)
36 {
37 if (!flag1)
38 {
39 odd1 = a[j];
40 flag1 = true;
41 }
42 else
43 odd1 ^= a[j];
44 }
45 else
46 {
47 if (!flag2)
48 {
49 odd2 = a[j];
50 flag2 = true;
51 }
52 else
53 odd2 ^= a[j];
54 }
55 }
56 }
57
58 /*
59 *
60 */
61 int main(int argc, char** argv)
62 {
63 int a[] = {4, 5, 3, 4, 5, 7, 7, 6, 8, 8};
64 int odd1, odd2;
65 findOutTwoOdds(a, 10, odd1, odd2);
66 cout << odd1 << " " << odd2 << endl;
67 return 0;
68 }
在写代码的时候,最好不要起一些容易混淆的变量名。我在编写该程序的时候,就范了该错误,调了好久才调好!
![Creative Commons License](http://i.creativecommons.org/l/by/2.5/cn/88x31.png)
本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名小橋流水(包含链接)。如您有任何疑问或者授权方面的协商,请给我发邮件。