对于这个题目:
异或的性质:对于整数a,有
- a^a=0
- a^0=a
- 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