C++ 演算法之 陣列中只出現一次的數字
阿新 • • 發佈:2018-12-26
題目:
一個整型數組裡除了兩個數字之外,其他的數字都出現了兩次。請寫程式找出這兩個只出現一次的數字。要求時間複雜度為O(n),控制元件複雜度為O(1)
演算法思路:
如果一個數組當中,只要一個數字出現一次,其他都是出現兩次,那麼我們只要把所有的數進行異或得到的就是結果
現在有兩個數字出現一次,那麼我們還是異或所有的數,最後的到的結果就是這兩個不想等的數字的異或結果
比如 2 4 3 6 3 2 5 5 最後異或就是 4 與 6 異或,那麼它們兩個異或的結果肯定不是0;也就是說這個結果數字的二進位制
當中至少有一位是1;我們在這個結果數字當中找到第一個為1的位置,記為第n位,現在我們以第n位是不是1把原來的
陣列分為兩部分;再分別異或兩個陣列;
分組異或:
比如int a[] = {1, 1, 3, 5, 2, 2}
整個陣列異或的結果為3^5即 0x0011 ^ 0x0101 = 0x0110
對0x0110,第1位(由低向高,從0開始)就是1。因此整個陣列根據第1位是0還是1分成兩組。
a[0] =1 0x0001 第一組
a[1] =1 0x0001 第一組
a[2] =3 0x0011 第二組
a[3] =5 0x0101 第一組
a[4] =2 0x0010 第二組
a[5] =2 0x0010 第二組
第一組有{1, 1, 5},第二組有{3, 2, 3},明顯對這二組分別執行“異或”解法就可以得到5和3了。
實現這個程式碼的假設條件就是 陣列當中不會出現兩個以上只出現1次的數字,比如 1 2 3 4 5 6 7 8 這種情況是無法處理的!// FindNumAppearOnce.cpp : 定義控制檯應用程式的入口點。 // #include "stdafx.h" #include <iostream> using namespace std; //找到第一個為1的位置 unsigned int FindFirstBitis1(int num) { int indexBit = 0; while (((num & 1) == 0) && (indexBit < 8 * sizeof(int))) { num = num>>1; ++indexBit; } return indexBit; } bool IsBit1(int num , unsigned int indexBit) { num = num >> indexBit; return (num & 1); } void FindNumAppearOnce(int array[], int nLength, int& num1, int& num2) { if (array == NULL || nLength < 2) { return; } int resultXOR = 0; for (int i = 0; i < nLength; i++) { resultXOR ^=array[i]; } //找到抑或結果數字當中的第一個1的位置 unsigned int indexOf1 = FindFirstBitis1(resultXOR); num1 = num2 = 0; for (int j = 0; j < nLength; ++j) { if (IsBit1(array[j],indexOf1)) { num1^=array[j]; } else { num2^= array[j]; } } } int _tmain(int argc, _TCHAR* argv[]) { int array[] ={4,6,1,1,1,1}; int i = 0; int j = 0; FindNumAppearOnce(array,sizeof(array)/sizeof(array[0]),i,j); if (i == 0 && j != 0) { cout<<"您輸入的陣列的當中出現1次的只有一個數字,它是:"<<j<<endl; } else if (j == 0 && i != 0) { cout<<"您輸入的陣列的當中出現1次的只有一個數字,它是:"<<i<<endl; } else if (i == 0 && j == 0) { cout<<"您輸入的陣列當中沒有隻出現一次的數字"<<endl; } else { cout<<"您輸入的陣列當中只出現1次的兩個數字是"<<i<<" "<<j<<endl; } getchar(); return 0; }