題目描述
一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。
思路
- 首先需要注意到數組中只有兩個數字出現了一次,其他都出現了兩次
- 其次:異或運算:兩個相同的數字進行異或運算等於0,0和其他數字異或運算都等於其他數字本身
- 因此如果我們將數組所有的數字全部進行異或運算例如數組{2, 4, 3, 6, 3, 2, 5, 5},也就是2^4^3^6^3^3^2^5^5 = 0010,異或的結果肯定是會出現一個1或者多個1以上,因爲異或的結果是由兩個只出現一次的數字決定的,其他出現兩次的數字運算後都爲0,對結果沒有影響。對於出現多個1的問題,我們可以從右邊開始,找到第一個1的下標(從左邊開始也是可以的),因此通過判斷數組中每一個數字的下標是否爲1或爲0,從分成兩個不同的數組(例如上例:{2,2,6,3,3}和{4,5,5}),這樣兩個數組就各自有一個只出現一次的數字,這樣是必然的,因爲我們是根據異或結果中的1的下標進行分類的,例如假設只出現一次的數字爲1和3,那麼異或運算就是010了,這個1的位置也就是將二進制第二位的判斷將1和3分類開了。
- 最後求兩個數組的異或結果就是出現一次的數字
- 注意問題: ==優先級比&大,函數參數傳指針,調用時需要傳地址
AC代碼
#include <iostream>
#include <vector>
using namespace std;
class Solution
{
public:
void FindNumsAppearOnce(vector<int> data, int *num1, int *num2)
{
int all_numbers_xo = 0; //所有數字進行異或運算的結果
for (int i = 0; i < data.size(); i++)
all_numbers_xo ^= data[i];
//結果是一個二進制數,至少存在一個1或多個1,我們可以從右邊開始找到第一個1的下標(也可以從左邊)
int index = 1;
while ((all_numbers_xo & index) == 0)
{
index <<= 1; //左移
// all_numbers_xo >>= 1; //右移
}
//根據數組中的數字的index位是否爲1或者0分爲兩個數組,因爲對這個index爲1或者爲0有影響的是兩個只出現一次的數字
//因此從這個兩個數組就可以各自求出各自只出現一次的數字,進行異或操作即可
*num1 = *num2 = 0;
for (int i = 0; i < data.size(); i++)
{//判斷條件不能寫成==1
if ((data[i] & index) != 0) //說明這個數字是屬於index爲1的數組的
*num1 ^= data[i];
else
*num2 ^= data[i];
}
}
};
int main()
{
vector<int> data = {2, 4, 3, 6, 3, 2, 5, 5};
int num1, num2;
Solution so;
so.FindNumsAppearOnce(data, &num1, &num2);
cout << num1 << " " << num2 << endl;
return 0;
}