您的位置:首页 > 其它

把一个连续数序列打乱判断少了那些数

2012-05-21 15:31 260 查看
/article/4462788.html


. 问题:100个连续的数打乱之后,随机取出1个数,问如何最快速的判断出少了哪一个?

分析:对于所有100个连续的数,只要除余100。一定在0~99之间。一般来说,比较常规的做法就是先排序(利用Hash表定位),在循环查找。当然时间复杂度是O(2n)。现在介绍一种很牛的O(n)做法:求二进制异或运算。

异或运算: 0^0=1^1=0; 0^1=1^0=1。0~99个数全部异或的结果只能是0。如果缺少一个数,那么全部异或的结果正好就是那个数。为什么呢?我们做个小实验:假如有四个数: 0001 0010,0101, 0110 排列成一个matrix.

bits: 1 2 3 4

0 0 0 1

0 0 1 0

0 1 0 1

0 1 1 0

全部异或: 0 0 0 0

我们可以下结论了,要全部异或的结果为0,那么所有bit位上的1的个数必须为偶数。反过来说:如果其中有一个数不存在了(比如0001),那么少0的的bit位上的值不变(因为1的个数还是偶数),而少1的bit位上的值就变成了1(1的个数为奇数了)。

在这里我又想到了以前遇到的几个使用异或来进行运算的例子:

第一个:使用异或交换两个数字的值

第二个:使用异或来选择两个数中的较大或较小者

第三个:一个序列中有奇数个数字,只有一个单独出现其他都是成对出现,快速找出这个单独出现的数字

这样0~99的道理也就一样了,所以异或的结果就是少的那个值。代码如下:

int data=0;
for (int i=0;i<=99;i++)
{
if(70==i)
continue;
data=data^i;
}
cout << data << endl;

2. 问题:100个连续的数打乱之后,随机取出2个数,问如何最快速的判断出少了哪两个? (注意少2个数了)

分析:常用的做法可以先创建一个100个结构的Hash表,然后循环一次将所有数哈希100之后的位置上置1。然后顺序循环100次查找这个Hash表。前后需要O(2n)的时间。然而有没有更快速的做法呢?当然,直接操作bit.

假设我们有32个连续打乱的数字(0~31)缺少两个数2和11,希望把标记1标记在一个32位上。也就是一个整形变量,标记完之后就成为了:

bits position 31 30 29 28 ....... 11 10 .... 2 1 0

int a= 1 1 1 1 ....... 0 1 .... 0 1 1 (缺少数的bit位上为0)

至于如何标记成为a,我们可以看看下面的小段代码:

#include <iostream>
#include <stack>
using namespace std;
typedef stack<int> sInt;

sInt toBinary(unsigned int n){
sInt s;
int i=n/2;//记录商值
int j=n%2;//记录余数
while(1)
{
s.push(j);
if(0==i)
break;
j=i%2;
i=i/2;
}
return s;
}

int main(){
unsigned int bits=0;
for (int i=0;i<32;i++)
{
unsigned int bitMove=1;
if(i==2||i==11)
continue;
bitMove=bitMove<<i;
bits=bits|bitMove;
}
sInt sTmp;
sTmp=toBinary(bits);
while (!sTmp.empty())
{
cout << sTmp.top();
sTmp.pop();
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐