C語言實現一個int類型數組裏除了兩個數字以外,其餘的數字都出現了兩次,找出這兩個數字

題目是這樣敘述的:
在一個數組中除兩個數字只出現1次外,其它數字都出現了2次, 要求儘快找出這兩個數字。數組

要求:時間複雜度爲O(N),空間複雜度爲O(1)。ide

請看個人分析:
將這道題簡單化:
一個數組中只有一個數字出現一次,其餘數字都是成對出現的,這時咱們能夠根據異或運算符的特性:A^B^A = B; 0 ^ A = A;咱們能夠將這個數組的所有元素依次作異或運算,最終結果就是那個只出現一次的數字。
不會的可看本人(2019-04-04)那天的博客 code

若是這個數組中出現兩個不一樣的數字,而其餘數字均出現兩次,假設這兩個數字分別是x, y。那若是能夠將x, y分離到兩個數組。這時這道題就變成兩個咱們簡化以後的版本中的數組了。這樣問題就能夠獲得解決了。因爲x,y確定是不相等的,所以在二進制上一定至少有一位是不一樣的。根據這一位是0仍是1能夠將x,y分開到A組和B組。而且數組中其餘元素也能夠根據這個方法劃分到兩個數組中。這時將兩個數組分別作異或運算,結果就是這兩個數字。
#include<stdio.h>

#define SIZE(arr) sizeof(arr)/sizeof(arr[0])

void find_num(int *arr, int len,int *num1,int *num2)
{
    int i;
    int sum = 0;
    for (i = 0; i < len; i++)
    {
        sum^=*(arr + i);//異或出全部數字
    }
    int j;
    for (j = 0; j < sizeof(int)* 8; j++)//int類型數組的字節數32
    {
    //if(sum>>j&1==1)也正確,不知道優先級,儘可能加上,下面同樣
        if (((sum >> j) & 1) == 1)//說明sum在右移 j 個單位後,二進制不同
        {
            break;
        }
    }
    for (i = 0; i < len; i++)
    {
        if (((*(arr + i) >> j) & 1) == 1)
        {
            *num1 ^= (*(arr + i));//異或 j 位置爲1的一組數字
        }
        else
        {
            *num2 ^= (*(arr + i));//異或 j 位置爲0的一組數字
        }
    }
}

int main()
{
    int arr[] = { 1, 3, 5, 7, 1, 3, 5, 9 };
    int num1=0, num2=0;
    find_num(arr,SIZE(arr),&num1,&num2);
    printf("%d %d", num1, num2);
    return 0;
}

總結:複雜問題簡單化,把兩個出現一次的數字分割爲兩組出現一次的數組博客

相關文章
相關標籤/搜索