劍指offer-數組中只出現一次的數字

題目描述

一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。

思路

  • 首先需要注意到數組中只有兩個數字出現了一次,其他都出現了兩次
  • 其次:異或運算:兩個相同的數字進行異或運算等於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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章