Bootstrap

位运算(binary_op)


(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) & 
;