位运算详解

1. 运算符

<<:左移运算符,左边移出的位被丢弃,右边空出的位用 0 填充。

>>:右移运算符,将左边的操作数的二进制表示向右移动右边操作数指定的位数。

~:按位取反,将操作数的二进制表示中的每一位进行取反操作

&:与运算,有 0 结果就是 0

|:或运算,有 1 结果就是 1

^:亦或,相同为 0,相异为 1 / 不进位相加

2. 基本操作

191,338,461,136,260

给定一个数 n,确定它的二进制表示中第 x 位是 0 还是 1

(n >> x) & 1

给定一个数 n,把它的二进制表示的第 x 位修改为 1

n |= (1 << x)

给定一个数 n,把它的二进制表示的第 x 位修改为 0

n &= (~ (1 << x))

提取一个数 n 二进制表示中最右边的 1

n & -n ( -n 就是将最右侧的 1 左边全部变成相反的,右边不变)

给定一个数 n ,把最右侧的 1 变成 0

n & (n - 1)

亦或(^)运算符运算律

  1. a ^ a = 0
  2. a ^ 0 = a
  3. a ^ b ^ c = a ^ (b ^ c)

3. 例题解析

a. 面试题 01.01. 判定字符是否唯一

面试题 01.01. 判定字符是否唯一

如果使用数据结构的话很明显就是放到哈希表中,然后再遍历哈希表进行查找,如果不使用数据结构的话可以通过使用位图的方式来替代哈希表,26 个比特位代表 26 个字母(1 表示该字符已经出现过,0 就表示没有出现过),在遍历字符串的同时进行判断,如果说出现过就直接放回 false ,如果没有就把该位设置为 1

java 复制代码
class Solution {
    public boolean isUnique(String astr) {
        if(astr.length() > 26) return false;
        char[] chars = astr.toCharArray();
        int bitMap = 0;
        for(int i = 0;i < chars.length;i++){
            int x = chars[i] - 'a';
            if((bitMap >> x & 1) == 1) return false;
            else bitMap |= (1 << x);
        }
        return true;
    }
}

b. 丢失的数字

268. 丢失的数字

方法一:使用哈希表,遍历数组,把数组中的数存在哈希表中并设为 1,再从 0 ~ n 进行遍历,查询哪一位为 0

方法二:高斯求和,把 0 ~ 1 的数进行求和,之后再把数组中的元素都减掉,最后剩的即为所求

方法三:位运算

先把 0 ~ 1的数都进行亦或运算,然后再遍历数组,再进行一次亦或运算,由于 a ^ a = 0,所以重复出现的都被变为 0 了,最后再根据 a ^ 0 = a 知道,剩余的数肯定就是答案了

java 复制代码
class Solution {
    public int missingNumber(int[] nums) {
        int ans = 0;
        for(int i = 0;i <= nums.length;i++){
            ans ^= i;
        }
        for(int i = 0;i < nums.length;i++){
            ans ^= nums[i];
        }
        return ans;
    }
}

c. 两整数之和

371. 两整数之和

由于题中限制了不能使用 + ,- ,所以可以考虑位运算来解决,在开始提到过亦或操作可以看做是无进位相加,所以只需要把进位找到就行,经过分析发现,只有 1 和 1 的情况会出现进位,也就符合了 & 运算,但此时只是表示哪一位发生了进位,所以需要把结果左移再加上无进位相加的结果即可,不过此时还可能会出现进位,所以上述操作需要重复计算,直到没有进位为止

java 复制代码
class Solution {
    public int getSum(int a, int b) {
        while(b != 0){
            int ans = a ^ b;
            int up = (a & b) << 1;
            a = ans;
            b = up;
        }
        return a;
    }
}

d. 只出现一次的数字 II

137. 只出现一次的数字 II

从每一个二进制位相加开始看,所有的数相加最后会有四种情况,把这些情况都 % 3 之后发现,结果和最后剩余那个只出现一次的数的位置相同,所以也就可以从每一个二进制位入手,把所有的数字加起来 % 3,得出每一位的结果,并把目标位设置为结果,最后就是只出现一次的那个数

java 复制代码
class Solution {
    public int singleNumber(int[] nums) {
        int ans = 0;
        for(int i = 0;i < 32;i++){
            int sum = 0;
            for(int x : nums){
                if(((x >> i) & 1) == 1){
                    sum ++;
                }
            }
            if(sum % 3 == 1) ans |= (1 << i);
        }
        return ans;
    }
}

e. 面试题 17.19. 消失的两个数字

面试题 17.19. 消失的两个数字

如果这道题转换一下,先把从 1 到 N 的数亦或,再把结果和 nums 数组亦或,结果也就变成了 nums 数组的数出现了两次,其他的数(也就是缺失的数)出现了一次,就转化为了求消失的两个数字,最终的亦或结果是缺失的那两个数的亦或结果,其中一定可以找到二进制位为 1 的那一位,也就可以把所有的数根据这个位置分为两组,这样也就能够把缺失的这两个数分开,就转化为了找缺失的一位的数,把所有结果亦或,最终就是缺失的那个数字,再求另一组即可

java 复制代码
class Solution {
    public int[] missingTwo(int[] nums) {
        int tmp = 0;
        //把 1 ~ n 的数亦或
        for(int i = 1;i <= nums.length + 2;i++){
            tmp ^= i;
        }
        //加上数组的数亦或
        for(int i = 0;i < nums.length;i++){
            tmp ^= nums[i];
        }
        //找到第一个为 1 的二进制位
        int diff = 0;
        while(true){
            if(((tmp >> diff) & 1) == 1) break;
            else diff++;
        }
        int[] ans = new int[2];
        //数组的数分组亦或
        for(int i = 0;i < nums.length;i++){
            if(((nums[i] >> diff) & 1) == 1) ans[0] ^= nums[i];
            else ans[1] ^= nums[i];
        }
        //1 ~ n 的数分组亦或
        for(int i = 1;i <= nums.length + 2;i++){
            if(((i >> diff )& 1) == 1) ans[0] ^= i;
            else ans[1] ^= i;
        }
        return ans;
    }
}
相关推荐
一路向北North40 分钟前
Java使用replaceAll替换时不使用正则表达式
java·开发语言·正则表达式
yangfeipancc41 分钟前
正则表达式
java·开发语言·正则表达式
jay丿1 小时前
正则表达式
服务器·mysql·算法·正则表达式·php
Duck Bro2 小时前
MySQL:常用数据类型
java·数据库·c++·mysql·java-ee
double丶flower2 小时前
设置Mysql5.6允许外网访问
java·mysql
kitesxian2 小时前
Leetcode53. 最大子数组和(HOT100)
数据结构·算法·leetcode
Cosmoshhhyyy3 小时前
Jackson库中JsonInclude的使用
java·开发语言
007php0073 小时前
GoZero对接GPT接口的设计与实现:问题分析与解决
java·开发语言·python·gpt·golang·github·企业微信
重生之我在VS写bug4 小时前
【C++知识总结2】C++里面的小配角cout和cin
数据结构·c++·算法
HUT_Tyne2654 小时前
力扣--LCR 141.训练计划III
算法·leetcode·职场和发展