**:c++異或運算在演算法中的經典運用
「乙個整型陣列裡除了兩個數字之外,其他的數字都出現了兩次。請寫程式找出這兩個只出現一次的數字?」這是經典的演算法題,乍看這個題的思路特別多。
比如首先排序、然後在查詢不同的資料就能找到這兩個數字,這種實現方法的時間複雜度應該是在o(nlgn),因為比較排序的演算法最好的時間複雜度就是這樣。但是乍一看,這題就解決了,但是還沒有充分運用乙個條件,絕大多數元素是成對出現的,這個條件的作用是什麼呢? 當然還有的思路就是hashmap實現,這種實現方法就是採用hash表儲存每個變數的次數,最後遍歷hash表即可,但是這種方法也存在問題,如果存在負數,或者陣列元素的值特別大,採用hashmap實現的空間複雜度太大,並不是我們需要的解決方式,hashmap適合的方式是在一定範圍類的數值進行統計。上面這兩種方法可能是比較快速想到的。
這道題的實現方法很多,關鍵是找到最好的實現方法很難,本文就介紹採用異或運算實現這道題目的解法。
異或運算是c語言中位運算的一種操作,這種操作對於嵌入式程式設計師可能比較熟悉,但是對於一般的程式設計師可能運用的比較少,異或操作具有如下的特徵:
0^num = num; 1^num = ~num; num ^ num = 0; 其中num = 0或者1。
運用結合律等特徵有:
a^a^b^b^c = (a^a)^(b^b)^c=0^0^c=c;
需要注意:如果有a + b = c; 則有可能使得a ^ b ^ c = 0;這個條件是非充分非必要,比如a = 1,b = 2, c = 3,這時候的a ^ b ^ c = 0是成立的,但是a = 2, b = 2, c = 4,則是不成立的。
從上面的結合律可以知道如果兩個相同的數進行異或操作結果是0,根據題目中元素是成對出現的,可以充分運用異或操作的結合特性,陣列元素異或以後的結果肯定會包含兩個不成對元素的特徵。
假設陣列元素為a[n],其中n的值很大,不成對的元素為an,am。實現上述過程的步驟如下所示:
首先,變數元素對所有元素進行異或操作,得到的結果肯定是an^am。也就說通過異或操作以後,結果中儲存了an和am的特徵。由於am和an不同,am^an的結果肯定是大於等於1。am和an不同,那麼am^an中為1的某乙個bit肯定是am或者an中某乙個的特徵。
然後,定義兩個值num1,num2,分別用來計算an、am,選擇am^an中的某乙個bit作為特徵位,假設是第k位是特徵位,再次對元素進行遍歷,如果元素的第k位是1,這個元素可能是am或者an,那麼將當前元素與num1進行異或操作,如果元素的第k為不為0,那麼這個元素則可能是另乙個值,那麼將當前元素與num2進行異或操作。這樣遍歷完所有元素,因為大部分資料成對出現,根據異或運算的特徵,num1,num2就分別儲存了兩個不同的值。
由上面的分析可知,這種演算法只需要遍歷兩次陣列空間即可實現資料的判定,這樣時間複雜度為o(n),同時因為沒有hashmap之類的結構體,這樣空間複雜度就是o(1)。這種演算法的實現肯定是最佳的。相比前面提到的hashmap、排序演算法時間複雜度和空間複雜度都要小,因此這種演算法的實現應該是最佳的。
#include#includeint whichbitone(int in)
int isbitone(int in, int k)
void xortest(int *array, int size)
/*得到第乙個數*/
printf("first data is %d\n",num1);
printf("second data is %d\n",num2);
}}int main(int argc, char *argv)
; xortest(array,10);
return 0;
}
上面的**基本上實現了上面的描述。
對於本題的另乙個變換「陣列中元素成對出現,但是存在三個不成對的元素,如何快速的找出這三個元素?」
這個題看起來和本題有一定的聯絡性,甚至我認為我們可以採用相同的方法找出三個值,但是後來發現這種方法存在乙個問題,但是三個的情況要遠遠比兩個的複雜,因為其中存在的可能性要多很多,不是不是屬於這個元素就是另乙個元素的問題,雖然這種解法可能導致問題產生,但是還是有可能解決的,除了當三個元素的異或結果為0,即x^y^z = 0時,這種方法是不成立的。
對於三個不同元素的找份,我認為主要是找到其中的乙個元素,然後將這個元素移除,在進行上述的另外兩個元素尋找。當然我們首先排除三個資料異或為零的特殊情況。www.it165.net
還是存在這個問題,如果這三個元素異或以後的值剛好為零,這種方法不能解決了,因此採用異或解決只有乙個不成對或者兩個不同元素的問題是沒有問題的,對於三個元素具有一定的可行性,但是不一定時時成立。
異或運算在演算法中針對的問題也是特定的,主要是這種元素成對出現的問題,如果不成對出現,這種演算法的實用性能會大大的降低,即使是重複元素都不一定是實用的。
異或運算的運用
背景1 最多有1e6 1個數,其中只有乙個數出現了奇數次,請找出這個數 資料大小為 int 範圍 利用原理 兩個相同的數異或值為0 解決方案 將所有數異或一次,最後得到的值就是出現奇數次的那個數 複雜度o n 背景2 最多有1e6個數,其中有兩個數出現了奇數次,請找出這兩個數 資料大小為 int 範...
異或運算在程式設計中的應用
1.只出現一次的數字 給定乙個非空整數陣列,除了某個元素只出現一次以外,其餘每個元素均出現兩次。找出那個只出現了一次的元素。說明 你的演算法應該具有線性時間複雜度。你可以不使用額外空間來實現嗎?示例 1 輸入 2,2,1 輸出 1 示例 2 輸入 4,1,2,1,2 輸出 4 題目 2.缺失數字 給...
C語言異或運算在程式設計中的妙用
異或運算子 也稱xor運算子。它的規則是若參加運算的兩個二進位同號,則結果為0 假 異號則為1 真 即0 0 0,0 1 1,1 1 0。性質 1 與1異或會翻轉 2 與0異或保持不變 3 乙個數異或它本身等於0 4 每一位的結果只與該位有關。應用 1 使特定位翻轉 假設有01110101,現在想讓...