(JAVA版本)
1 常见二进制操作
基本操作
a = 0 ^ a = a ^ 0
0 = a ^ a
由上面两个推导出:a = a ^ b ^ b
交换两个数
a = a ^ b
b = a ^ b
a = a ^ b
移除最后一个 1
a = n & (n-1)
获取最后一个 1
diff = (n & (n-1)) ^ n
位运算
符号 | 描述 | 运算规则 |
---|---|---|
& | 与 | 两个位都为1时,结果才为1 |
| | 或 | 两个位都为0时,结果才为0 |
^ | 异或 | 两个位相同为0,相异为1 |
~ | 取反 | 0变1,1变0 |
<< | 左移 | 各二进位全部左移若干位,高位丢弃,低位补0 |
>> | 右移 | 各二进位全部右移若干位,对无符号数,高位补0,有符号数,各编译器处理方法不一样,有的补符号位(算术右移),有的补0(逻辑右移) |
2 位运算常见题型
2.1 (lee-136) 只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
输入: [2,2,1]
输出: 1
(1)位运算
/*
* 方法1.使用^符号,相同为0,不同为1
*/
public int singleNumber(int[] nums) {
int res = 0;
for(int num : nums) {
res = res ^ num; // 两个相同的数做异或操作等于0,0与任何数异或,数值不变。
}
return res;
}
(2)HahMap
/*
* 方法2:使用HashMap中map.getOrDefault();
*/
public int singleNumber(int[] nums) {
HashMap<Integer,Integer> map = new HashMap<>();
for(int i = 0;i < nums.length;i++) {
int a = map.getOrDefault(nums[i], 0);
map.put(nums[i], a+1);
}
for (int num : map.keySet()) {
if(map.get(num)==1) {
return num;
}
}
return -1;
}
/*
* 方法3:使用hashMap中containsKey
*/
public int singleNumber(int[] nums) {
HashMap<Integer,Integer> map = new HashMap<>();
for(int i = 0;i < nums.length;i++) {
if(!map.containsKey(nums[i])) {
// 如果之前没有遇到这一数字,则放入 map 中
map.put(nums[i], 1);
}else {
map.put(nums[i], map.get(nums[i])+1);// 如果之前遇到过这一数字,则出现次数加 1
}
}
for(int num : map.keySet()) {
if(map.get(num)==1) {
return num;
}
}
return -1;
}
2.2 (lee-137) 只出现一次的数字2
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了 三次 。找出那个只出现了一次的元素。
输入:nums = [2,2,3,2]
输出:3
(1)位运算
时间复杂度O(n)
空间复杂度O(1)
//方法1.用^、~、&运算,数字电路的思想
//不太理解????
public int singleNumber(int[] nums) {
int once = 0;
int twice = 0;
for(int num:nums) {
once = (once ^ num) & ~twice; // 只出现一次的数按照下面的规则运算后,once就等于该数。
twice = (twice ^ num) &