-
>>
带符号位右移 高位根据符号位补齐 -
>>>
不带符号位右移 高位都用0补齐 -
mid = (L + R) / 2
写成mid = L + ((R-L) >> 1)
防止溢出 -
n * 2
可以写成n << 1
-
(n * 2)+1
可以写成((n << 1) | 1)
异或运算
异或运算:相同为0,不同为1
同或运算:相同以1,不同为0
所以,异或运算就记成无进位相加!
-
异或运算的性质
0^N == N
N^N == 0
异或运算满足交换律和结合率(同一批数,异或起来的结果是一样的)
上面的两个性质用无进位相加来理解就非常的容易 -
如何不用额外变量交换两个数 (a,b在不同内存)
a = a ^ b;
b = a ^ b;
a = a ^ b;
- 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数
准备一个 int eor = 0;
与数组中的所有数异或,最后eor的值就是这种数。
因为偶数的本身异或都为0了,奇数异或是本身。
// arr中,只有一种数,出现奇数次
public static void printOddTimesNum1(int[] arr) {
int eor = 0;
for (int i = 0; i < arr.length; i++) {
eor ^= arr[i];
}
System.out.println(eor);
}
- 怎么把一个int类型的数n,提取出最右侧的1来
用 n & ((~n) + 1);
n = 0 ... 0 1 1 0 1 0 1 0 0 0 0
~n = 1 ... 1 0 0 1 0 1 0 1 1 1 1
~n+1 = 1 ... 1 0 0 1 0 1 1 0 0 0 0
ans = 0 ... 0 0 0 0 0 0 1 0 0 0 0
- 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数
假设2种数是a,b.
eor 先与数组所有数异或,那么eor = a ^ b != 0,那么 a,b中一定有一位是不一样的,假设他们第8位不一样。
整个数组可以分为
1.第8位=1的
2.第8位=0的
那么a,b是在这2个不同的组。
再找有个变量 eor‘ 去同第一组异或,那第一组中偶数的都为0了,剩下的结果就是eor’ = a(设a分在第一组)。
那么 eor ^ eor' = b.
// arr中,有两种数,出现奇数次
public static void printOddTimesNum2(int[] arr) {
int eor = 0;
for (int i = 0; i < arr.length; i++) {
eor ^= arr[i];
}
// eor = a ^ b
// eor != 0
// eor必然有一个位置上是1
// 0110010000
// 0000010000
int rightOne = eor & (~eor + 1); // 提取出最右的1
int onlyOne = 0; // eor'
for (int i = 0 ; i < arr.length;i++) {
// arr[1] = 111100011110000
// rightOne= 000000000010000
if ((arr[i] & rightOne) != 0) {
onlyOne ^= arr[i];
}
}
System.out.println(onlyOne + " " + (eor ^ onlyOne));
}
- 计算二进制中有几个1
public static int bit1counts(int N) {
int count = 0;
// 011011010000
// 000000010000 1
// 011011000000
//
while(N != 0) {
int rightOne = N & ((~N) + 1);
count++;
N ^= rightOne;
// N -= rightOne
}
return count;
}
网友评论