算法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=1101b=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)。

相关推荐
Navigator_Z1 小时前
LeetCode //C - 1224. Maximum Equal Frequency
c语言·算法·leetcode
Navigator_Z2 小时前
LeetCode //C++ - 1226. The Dining Philosophers
c语言·算法·leetcode
FOORIR2 小时前
3D视觉+AI客流系统怎么做:从Sensor Pipeline到数据事件引擎
算法
Omics Pro4 小时前
Arc研究所Cell|全新虚拟细胞官方基准评测框架
大数据·人工智能·深度学习·算法·机器学习
CoderYanger6 小时前
A.每日一题:1140. 石子游戏 II
java·程序人生·算法·leetcode·游戏·职场和发展·深度优先
小雨笙笙6 小时前
机器学习:评估模型与选择
人工智能·算法·机器学习
高亦真6 小时前
今天是学习嵌入式的第35天
linux·学习·算法
HugoStudio_SWAN6 小时前
洛谷 P1319 / P1320 压缩技术——同一枚硬币的正反面
c++·学习·程序人生·算法
wdfk_prog8 小时前
canopennode-rtt推荐,不只可以做从站,也可以承担主站角色
c语言·开发语言·数据库·学习·算法·深度优先