题目描述:
Given an array of n integers, such that each number in the array appears exactly twice, except for three numbers (say a, b and c) which appear exactly once.
In O(n) time and O(1) space find a,b and c.
分析:
先看这样一道题:
n个数中有且仅有一个数出现了奇数次(其它数都出现了偶数次),如何用线性时间常数空间找出这个数。
解法如下:
从头到尾异或一遍,结果就是要求的那个数。(原理很清楚明了)
再看稍微加强版:
n个数中有且仅有两个数出现了奇数次(其它数都出现了偶数次),如何用线性时间常数空间找出这个数。
解法比较巧妙,主要思想是将元素分成两组,每组中有且仅有一个数出现了奇数次(其它数都出现了偶数次),然后应用上题的结论解答,至于如何分组,见下:
1、异或所有元素得xors
2、找出xors中不为0的一个bit位(通常从右向左找出第一个不为0的)
3、以2中找到的bit位为sentinel,将数组分为两组
本题:
思路类似于求解上题,关键是找出第一个来,然后借助上题结论求另外两个
// Let s = a ^ b ^ c. We know that s not in (a, b, c),
// since if s == a, say, then b ^ c == 0 and b == c.
// Let f(x) be the lowest bit where x differs from s.
// The algorithm computes flips = f(a) ^ f(b) ^ f(c),
// since the numbers appearing an even number of times cancel.
// The variable flips has parity 1, so it is non-zero,
// and lowbit(flips) is a bit where one or three of a, b, c
// differ from s. It can't be three, however, so the final
// exclusive-or includes exactly one of a, b, c.
代码:
#include <iostream>
using namespace std;
// get lowest different bit
int lowbit(int x)
{
return x & ~(x - 1);
}
// Given an array of n integers, such that each number
// in the array appears exactly twice, except for two
// numbers (say a and b) which appear exactly once.
//
// In O(n) time and O(1) space find a and b.
// e.g.
// { 2 3 3 2 4 6 4 7 8 8 } ---> a/b = { 6 7}
void Find2(int seq[], int n, int& a, int& b)
{
////XOR
int xors = 0;
for(int i = 0; i < n; i++)
xors ^= seq[i];
////get different bit
int diff = lowbit(xors);
////
a = 0;
b = 0;
for(int i = 0; i < n; i++)
{
if(diff & seq[i])
a ^= seq[i];
else
b ^= seq[i];
}
}
// Given an array of n integers, such that each number
// in the array appears exactly twice, except for three
// numbers (say a, b and c) which appear exactly once.
//
// In O(n) time and O(1) space find a,b and c.
// e.g.
// { 2 3 3 2 4 6 4 7 8 8 1 } ---> a/b = { 6 7 1}
// Let s = a ^ b ^ c. We know that s not in (a, b, c),
// since if s == a, say, then b ^ c == 0 and b == c.
// Let f(x) be the lowest bit where x differs from s.
// The algorithm computes flips = f(a) ^ f(b) ^ f(c),
// since the numbers appearing an even number of times cancel.
// The variable flips has parity 1, so it is non-zero,
// and lowbit(flips) is a bit where one or three of a, b, c
// differ from s. It can't be three, however, so the final
// exclusive-or includes exactly one of a, b, c.
void Find3(int seq[], int n, int& a, int& b, int& c)
{
////XOR
int xors = 0;
for(int i = 0; i < n; i++)
xors ^= seq[i];
////
int flips = 0;
for(int i = 0; i < n; i++)
flips ^= lowbit(xors ^ seq[i]);
flips = lowbit(flips);
////get one of three
a = 0;
for(int i = 0; i < n; i++)
{
if(lowbit(seq[i] ^ xors) == flips)
a ^= seq[i];
}
////swap a with the last element of seq
for(int i = 0; i < n; i++)
{
if(a == seq[i])
{
int temp = seq[i];
seq[i] = seq[n - 1];
seq[n - 1] = temp;
}
}
////call Find2() to get b and c
Find2(seq, n - 1, b, c);
}
int _tmain(int argc, _TCHAR* argv[])
{
int a,b,c;
int test1[] = { 2, 3, 3, 2, 4, 6, 4, 7, 8, 8 };
Find2(test1, 10, a, b);
cout<<"a = "<<a<<" , b = "<<b<<endl;
int test2[] = {1 , 2 , 3 };//{ 2, 3, 3, 2, 4, 6, 4, 7, 8, 8, 1 };
Find3(test2, 3, a, b, c);
cout<<"a = "<<a<<" , b = "<<b<<" , c = "<<c<<endl;
system("pause");
return 0;
}
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yysdsyl/archive/2009/06/22/4289828.aspx