目录
问题
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
问题来自力扣:https://leetcode-cn.com/problems/single-number/comments/
分析
1. 一般的法子是两次遍历解决问题,应该都会
2. 如果数字特殊,1,2,4,8 这类,加起来是可以根据结果来 判断 每个加数的
3. 要求一次遍历解决问题,只能计算,但什么样的计算呢
- 不看答案不太容易想到 ^,异或的
- 为啥能想到计算呢,是从交换数值来的思路,拥有5,3 和2,3 从信息角度看,信息并没有丢失,是一样的
位运算:^,异或
相同为0,不同为1,即
1 ^ 1 = 0
0 ^ 0 = 0
1 ^ 0 = 1
由运算规则可知,任何二进制数与零异或,都会等于其本身,即 A ^ 0 = A。
性质
(1)交换律: A ^ B = B ^ A
(2)结合律: ( A ^ B ) ^ C = A ^ ( B ^ C )
(3)自反性: A ^ B ^ B = A (由结合律可推: A ^ B ^ B = A ^ ( B ^ B ) = A ^ 0 = A)
应用
1. 交换数值
a = 1, b=2
A : 借助中间变量c
c = a; a = b; b = c;
B : 不借助中间变量
a = a + b; 3
b = a - b; 1
a = a - b; 2
C :使用异或
a = a ^ b
b = a ^ b = (a ^ b) ^ b
a = a ^ b = (a ^ b) ^ ((a ^ b) ^ b)
学习点:a + b - b = a ^ b ^ b
2. 数字序列中只一个数字没有重复
在一个整数数组中,仅存在一个不重复的数字
a ^ b ^ b ^ c ^ c ^ …… ^ z ^ z
= 如果顺序不一样可以根据交换律交换顺序
= a ^ (b ^ b ) ^ (c ^ c) ……
= a ^ 0 ^0 ……
= a
3.数字序列中只一个数字重复
将数字1-999存放在一个大小为1000的数组中,其中只有一个数字重复出现两次,找出重复数字。
看看规律就很清楚了,根据交换律知道:1 ^ 2 ^ … ^ 999 ^ n = 0 ^ n = n
能发现这个规律的前提是,你自己在本上写写二进制,稍微计算下就会发现,然后下边的其实只是为了文档进行的验证,自己学习还需要走这个路,只明白结论会很快忘记的,学会解决问题的方法才是最重要的。
i - 异或值 : 二进制
---------------------------------------------------
1 - 1 : 1
2 - 3 : 10
3 - 0 : 11
---------------------------------------------------
4 - 4 : 100
5 - 1 : 101
6 - 7 : 110
7 - 0 : 111
---------------------------------------------------
8 - 8 : 1000
9 - 1 : 1001
10 - 11 : 1010
11 - 0 : 1011
---------------------------------------------------
12 - 12 : 1100
13 - 1 : 1101
14 - 15 : 1110
15 - 0 : 1111
---------------------------------------------------
988 - 988 : 1111011100
989 - 1 : 1111011101
990 - 991 : 1111011110
991 - 0 : 1111011111
---------------------------------------------------
992 - 992 : 1111100000
993 - 1 : 1111100001
994 - 995 : 1111100010
995 - 0 : 1111100011
---------------------------------------------------
996 - 996 : 1111100100
997 - 1 : 1111100101
998 - 999 : 1111100110
999 - 0 : 1111100111
---------------------------------------------------
相关代码
int re = 0;
int temp = 90;
System.out.println(String.format("%5s - %5s : %20s", "i","异或值","二进制"));
System.out.println("---------------------------------------------------");
for(int i= 1; i < 1000 ;i++){
re ^= i;
/*if(i== 999){
re ^= temp;
System.out.println(i + " - " + re );
}*/
System.out.println(String.format("%5s - %5s : %20s", i,re,Integer.toBinaryString(i)));
if(re == 0){
System.out.println("---------------------------------------------------");
}
}
end