一個整型數組裏除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。要求時間複雜度是O(n),空間複雜度是O(1)

對於這個題目:

異或的性質:對於整數a,有

  1. a^a=0
  2. a^0=a
  3. a^b^c=a^(b^c)=(a^c)^b

思路:

1、思路:

(1)對於出現兩次的元素,使用“異或”操作後結果肯定爲0,那麼我們就可以遍歷一遍數組,對所有元素使用異或操作,那麼得到的結果就是兩個出現一次的元素的異或結果。

(2)因爲這兩個元素不相等,所以異或的結果肯定不是0,也就是可以再異或的結果中找到1位不爲0的位,例如異或結果的最後一位不爲0。

(3)這樣我們就可以最後一位將原數組元素分爲兩組,一組該位全爲1,另一組該位全爲0。 (4)再次遍歷原數組,最後一位爲0的一起異或,最後一位爲1的一起異或,兩組異或的結果分別對應着兩個結果。

2、複雜度:

(1)時間複雜度:第一次循環,將所有元素異或得到對應結果,時間開銷爲O(n);第二次循環,找出第一次異或結果爲1的位,時間開銷爲O(32);第三次循環,根據爲1的位將元素分爲兩組進行異或得到兩個結果,時間複雜度爲O(n),所以總的時間複雜度爲T(n) = 2*O(n)+O(32) = O(n)。

(2)空間複雜度:常數,因爲只分配了兩個空間用於結果的保存,因此空間複雜度爲常數。

答案:

 

$res = 0;
//$a = [0,1,4,2,4,2,33,33];
$a = [1,2,3,4,5,1,2,3];
print_r($a);


for($i=0;$i<count($a);$i++) {
    $res ^=$a[$i];//此結果爲兩個不同的數異或的結果值,如a,b,c,d,a,d四個數   a^b^c^d^a^d=(a^a)^(d^d)^c^b=0^0^c^b=c^b
}
//找到異或結果爲1的位,只需找一位即可比如0101,找最後一位就行;因爲有兩個數不同,那麼肯定有位爲1和0,這樣異或後結果爲1

//        $index = 0;
//        for(int i=0; i<32; i++) {  //找出亦或結果爲1的位。  
//            if((res>>i & 1) == 1) {
//                $index = i;
//                break;
//            }
//        }

$index = 0;
while(($res%2)&1 == 0){
    $res>>1;
    var_dump($res);
    $index++;
}
var_dump($index);
$num1=0;
$num2=0;
//1,3,5,1,3, 5
//2,4,2  4
//1:0001,0001,1   num1:1
//2:0010,0001,0    num2:2
//3:0011,0001,1, num1:1^3=0001, 0011=0010=2
//4:0100,0001,0, num2:2^4=0010,0100=0110=6
//5:0101,0001,1,num1:2^5=0010,0101=0111=7
//1:0001,0001,1 num1:1^7=0001,0111=0110=6
//2:0010,0001,0 num2=6^2=0110,0010=0100=4
//3:0011,0001,1 num1:6^3 = 0110,0011=0101=5;
//比如上面找到二進制最後一位爲1,現在遍歷數組,把二進制最後一位爲1和0的區分開來。
//如1,3,5,1,3的最後一位爲1,他們爲一組;2,4,2最後一位爲0,他們爲一組
//然後把每組的進行異或,比如上面第一組異或1^3^5^1^3=5,第二組異或:2^4^2=4
for($i=0;$i<count($a);$i++){
    if(($a[$i]>>$index) &1){
        $num1^=$a[$i];
        echo "num1:".$num1.PHP_EOL;

    } else{
        $num2^=$a[$i];
        echo "num2:".$num2.PHP_EOL;

    }
}
echo "n1:".$num1.PHP_EOL;
echo "n2:".$num2.PHP_EOL;

參考:https://www.cnblogs.com/hezhiyao/p/7539024.html

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章