一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是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

 

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