算法34,位运算符操作,总结

一、六种基础运算符

符号 名称 规则 典型用途
<< 左移 各二进制位左移,低位补 0 1 << x 造第 x 位的掩码
>> 右移(算术) 右移,高位补符号位​ 取第 x 位的值
>>> 右移(无符号) 右移,高位一律补 0 Java 特有,处理带符号数时救命
~ 按位取反 0↔1 全反转 配合 +1 造负数、造反掩码
& 与 同为 1 才 1 抹掉某些位
| 或 有 1 就 1 置上某些位
^ 异或 不同才为 1 翻转某些位、去重

补第一个坑 :>> 和 >>> 千万别混。对负数 >> 高位补 1,右移再多次也还是负数;>>> 高位补 0,能拿到无符号视角。判断第 x 位时用 >> 没问题,但若要遍历一个 long 的所有位,必须用 >>>。

二、判断二进制第 x 位是 0 还是 1

复制代码
int bit = (n >> x) & 1;

把第 x 位移到最低位,再用 &1 把其他位全抹掉。

三、把第 x 位改成 1 / 0

置 1(或上一个只有第 x 位为 1 的掩码)

复制代码
n |= (1 << x);

置 0(与上一个只有第 x 位为 0、其余全 1 的掩码)

复制代码
n &= ~(1 << x);

补第二个坑 :& 用来清零 ,| 用来置位 ,^ 用来翻转 。很多人写置 0 时下意识也用 ^,结果一旦该位本来就是 0,反而被翻成 1 了。

四、lowbit:提取最右侧的 1

复制代码
n & (−n)

原理 :计算机里 -n = ~n + 1。取反后最右那个 1 变成 0、它右边全变 1,再 +1 会一路进位,恰好把那个 1 重新顶回原位,于是原数和它的负数只在最右侧那个 1 处同时为 1。

用你笔记里的 011010100(即 212):

复制代码
n        = 011010100
~n       = 100101011
~n + 1   = 100101100
n & -n   = 000000100   → 4  ✓

用途:树状数组的核心、以及"只出现一次的数字 III"里拿来分组。

五、干掉最右侧的 1

复制代码
n & (n−1)

n-1 会把最右侧的 1 借位借掉,它右边全翻成 1:

复制代码
n        = 011010100
n - 1    = 011010011
n & (n-1)= 011010000   → 208  ✓

每执行一次就少一个 1,所以循环执行直到为 0,次数就是 1 的个数------这正是统计汉明权重的高效写法(比逐位判断快,跳过所有 0)。

六、异或三大性质

复制代码
a⊕0=aa⊕a=0a⊕b=b⊕a

再配上结合律 ​ (a^b)^c = a^(b^c),就有了整类"去重"题的解法:一堆数里成对出现的全抵消,剩下的就是落单的那个。

只出现一次的数字(其余都出现两次):全部异或一遍即可。

复制代码
public int singleNumber(int[] nums) {
    int ans = 0;
    for (int x : nums) ans ^= x;
    return ans;
}

只出现一次的数字 III (其余都出现两次,落单的有两个):先全部异或得到 a^b,再用 lowbit 把两个数分到不同组。

复制代码
public int[] singleNumber(int[] nums) {
    int xor = 0;
    for (int x : nums) xor ^= x;
    int lb = xor & -xor;           // 取最右侧的 1,它必然只属于 a、b 之一
    int a = 0, b = 0;
    for (int x : nums) {
        if ((x & lb) == 0) a ^= x; // 按这一位分成两组,各自组内成对抵消
        else               b ^= x;
    }
    return new int[]{a, b};
}

七、汉明距离

两个数不同位的个数 ​ = a ^ b 中 1 的个数(异或后为 1 的位正是二者不同的地方)。

复制代码
public int hammingDistance(int a, int b) {
    int x = a ^ b, cnt = 0;
    while (x != 0) {        // 每轮干掉最右侧的 1
        x &= x - 1;
        cnt++;
    }
    return cnt;
}

以 a=1101、b=1011 为例:a^b = 0110,含 2 个 1,汉明距离 = 2​ ✓

八、实战速查

想做的事 一行写法
取第 x 位 (n >> x) & 1
第 x 位置 1 n |= 1 << x
第 x 位置 0 n &= ~(1 << x)
第 x 位翻转 n ^= 1 << x
提取最右的 1 n & -n
干掉最右的 1 n & (n-1)
判断 2 的幂 n > 0 && (n & (n-1)) == 0
统计 1 的个数 循环 n &= n-1
不用临时变量交换 a^=b; b^=a; a^=b;

补第三个坑 :1 << 31 会溢出成负数(Integer.MIN_VALUE),位掩码涉及高位时用 1L << x。

配套题号:LC 191(位 1 的个数)、LC 231(2 的幂)、LC 461(汉明距离)、LC 136 / 137 / 260(只出现一次的数字 I / II / III)。

相关推荐
倒头就睡的小比特3 天前
算法竞赛C++常用的STL
c++·算法
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
猎头南楼3 天前
知识社区推荐系统实践:新用户冷启动与长短期兴趣建模的挑战 资深推荐算法工程师
人工智能·深度学习·算法·机器学习
旖旎夜光3 天前
力控面试题 01.01: 判定字符是否唯一(位运算) —— 题解
c++·学习·算法·leetcode·力控
wzdark3 天前
大规模并行计算中的负载均衡算法研究4
算法
Because_of_Her13 天前
并查集-听课笔记
笔记·算法·并查集
码流子3 天前
高速公路安全监测实践:碰撞监测预警+物联网底座,从感知到处置的闭环
大数据·人工智能·物联网·算法·架构
another heaven3 天前
【算法/C++ MD5算法能否逆解码?原理、C++实现与同类哈希算法对比】
c++·算法·哈希算法
wzdark3 天前
从算法设计模式看编程思维的抽象能力4
算法
2601_962218613 天前
万象生鲜系统称重自动多退少补算法解决生鲜非标品痛点
大数据·数据库·人工智能·python·算法