把一個連續數序列打亂判斷少了那些數

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;
}


 

 


發佈了231 篇原創文章 · 獲贊 36 · 訪問量 142萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章