概述
题目描述
一组带数字编号的球里除了两个编号之外,其它的编号都出现了两次。
请写程序找出这两个只出现一次的编号。要求时间复杂度是O(n),空间复杂度是O(1)。
输入描述:
整形数组
长度不超过1000000
输出描述:
输出数组中2个只出现了一次的数
先输出较小的数
示例1
输入
复制
1
2
3
4
5
2
3
4
5
6
输出
复制
1 6
一组带数字编号的球,其中有两个编号只出现了一次,把它们找出来例如 : [ 2, 3, 4, 5, 2, 3, 4, 5, 7, 8] 则 A=7, B=8
假设数组为
70 = 0100011
0
80 = 01010000
90 = 0101101
0
60 = 00111100
70 = 0100011
0
80 = 01010000
90 = 0101101
0
50 = 0011001
0
全部xor后
xor = 0000111
0
因为xor的最末尾1
是倒数第2
位,
我们把
- 所有倒数第
2
位为1
的归为一组用来亦或
得到ansA - 所有倒数第
2
位为0
的归为一组用来亦或
得到ansB
取最末尾1
的位置用lowbit
函数,
l o w b i t lowbit lowbit函数
- 树状数组常用
- l o w b i t ( x ) = x & ( − x ) lowbit(x) = x & (-x) lowbit(x)=x&(−x)
- 因为计算机用补码存取二进制数,而负数的补码为反码+1,举个例子
假如ret = 1110 , -ret = 0010 , 所以 i = 0010
代码如下
int A, B, XOR, a[MAXN];
#define lowbit(x) (x & (-x))
void slove() {
while(~scanf("%d ", &m) && ~m) a[++n] = m;
for(int i=1; i<=n; i++) XOR ^= a[i];
XOR = lowbit(XOR); // 取最后一位的 1
// 假设 xor = 110010100
// 则 lowbit(xor)=000000100
for(int i=1; i<=n; i++)
if(XOR & a[i]) A ^= a[i]; //把所有倒数第3位为1的分为一组 xor
else B ^= a[i]; //把所有倒数第3位为0的分为一组 xor
printf("%d %dn", min(A,B), max(A,B));
}
完整代码(多了很多不必要的演示代码)
#define debug
#ifdef debug
#include <time.h>
#include "/home/majiao/mb.h"
#endif
#include <iostream>
#include <algorithm>
#include <vector>
#include <string.h>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <math.h>
#define MAXN ((int)2e6+7)
#define ll long long
#define INF (0x7f7f7f7f)
#define fori(lef, rig) for(int i=lef; i<=rig; i++)
#define forj(lef, rig) for(int j=lef; j<=rig; j++)
#define fork(lef, rig) for(int k=lef; k<=rig; k++)
#define QAQ (0)
using namespace std;
#define show(x...)
do {
cout << "