异或
一.运算
异或运算:相同为0,不同为1。即**无进位相加 **
int a = 7;
int b = 13;
a ^ b = 10;
//转为二进制形式运算
// a : 0 0 1 1 1 = 7
// b : 0 1 1 0 1 = 13
//a^b: 0 1 0 1 0 = 10
二.性质
- 0 ^ N = N
- N ^ N = 0
- 交换律:a ^ b = b ^ a
- 结合律:( a ^ b ) ^ c = a ^ ( b ^ c )
- 由交换律和结合律可以推出:同样一批数不管以何种先后顺序异或在一起结果相同,a ^ b ^ c ^ d = c ^ d ^ b ^ a = F
三.常见面试题
题目一:如何不用额外变量交换两个数
- 正常解法:
int a;
int b;
int tmp = a;
a = b;
b = a;
- 异或运算
int a;
int b;
a = a ^ b; // (1)式
b = a ^ b; //代入(1) 由 N ^ N = 0和结合律可得 b = a ^ (b ^ b) = a;
a = a ^ b; //代入(1) 由 N ^ N = 0和结合律,交换律可得 a = a ^ b ^ a = (a ^ a) ^ b = b;
注意:用于数组中两数交换时需保证 arr[a] 和 arr[b] 的地址不同,a != b。数值相同可以使用。
题目二:一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数
- 正常解法:
- 思路:使用哈希表进行词频统计,最后判断哪个数出现了偶数次。
- 异或运算:
// 由性质:0 ^ N = N 和 N ^ N = 0 可知
// 出现偶数次的数都会因 N ^ N = 0而消掉,最后出现奇数次的数因 0 ^ N = N 而保留下来
int[] arr = {1, 1, 1, 1, 2, 2, 2, 3, 3, 4, 4, 5, 5}
int num = 0;
for (int i = 0; i < arr.length; i++) {
num ^= arr[i];
}
System.out.println(num); // 2
题目三:怎么把一个int类型的数,提取出最右侧的1来
可知 a & ( – a) = a & ( ~ a + 1) 即 – a = ~ a + 1
a = 0 1 1 0 1 1 1 0 0 1 0 0 0 0
~ a = 1 0 0 1 0 0 0 1 1 0 1 1 1 1 // ~ 取反
~ a + 1 = 1 0 0 1 0 0 0 1 1 1 0 0 0 0
a & (-a)= 0 0 0 0 0 0 0 0 0 1 0 0 0 0 // 令 a & (-a) 即可提取出
题目四:一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数
int[] arr = {1, 1, 3, 3, 4, 4, 5, 6, 6, 7, 7, 7};
int eor = 0;
//得到 eor = a ^ b
for (int i = 0; i < arr.length; i++) {
eor ^= arr[i];
}
// 由于 a 和 b 是两种数
// 所以 eor != 0
// 提取 eor 最右侧的1,由异或‘相同为0,不同为1’ 可知在该位置 a 和 b 不同时为 1
int rightOne = eor & (~eor + 1);
int onlyOne = 0;
// 根据最右侧eor为1位置的 按是否为1 异或出一组数
for (int i = 0; i < arr.length; i++) {
// arr[i] = 111100011110000
// rightOne = 000000000010000
if ((arr[i] & rightOne) != 0) {
onlyOne ^= arr[i];
}
}
// 可得到 onlyOne = a 或 b , eor ^ onlyOne = a ^ b ^ a(或者b),由此可区分两个数
System.out.println(onlyOne + " " + (eor ^ onlyOne));
题目五:一个数组中有一种数出现了 K 次,其他数都出现了 M 次,M > 1, K < M ,找到出现了 K 次的数,要求,额外空间复杂度O(1),时间复杂度O(N)
int[] arr = {1, 1, 1, 1, 4, 4, 4, 4, 2, 2, 2, 2, 8, 8, 8};
int k = 3;
int m = 4;
// 以二进制形式记录所有位次出现次数
int[] t = new int[32];
// 遍历统计
for (int num : arr) {
for (int i = 0; i <= 31; i++) {
// if (((num >> i) & 1) != 0) {
// t[i]++;
// }
//如果不为0 , 对应位为+1
t[i] += (num >> i) & 1;
}
}
// 记录结果
int ans = 0;
for (int i = 0; i < 32; i++) {
// 模 m 后 位次不为0,由于k < m,说明 目标数在该位置也出现了k次
if (t[i] % m != 0) {
// 通过 | 运算将 1 或入对应位
ans |= (1 << i);
}
}
System.out.println(ans);
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/82599.html