http://hxraid.iteye.com/blog/618153
. 問題: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;
}