当前位置: 首页 > news >正文

LeetCode算法日记 - Day 17: 算法中的位运算技巧总结

目录

1. 常见位运算

1.1 基础运算 

1.1.1 & 按位与

1.1.2 | 按位或

1.1.3 ^ 按位异或

1.1.4 ~ 按位取反

1.2 判断 n 的第 x 位是 0 还是 1

1.3 将第 x 位设为 1

1.4 将第 x 位设为 0

1.5 提取最右侧的 1(lowbit)

1.6 删除最右侧的 1

1.7 异或 ^ 的运算规律

2. 位 1 的个数

2.1 题目解析

2.2 解法

2.3 代码实现

3. 比特位计数

3.1 题目解析

3.2 解法

3.3 代码实现

4. 汉明距离

4.1 题目解析

4.2 解法

4.3 代码实现


1. 常见位运算

1.1 基础运算 

1.1.1 & 按位与

有零就是零,常用于筛选/清零

位运算二进制结果
1 & 111
1 & 000
0 & 100
0 & 000

1.1.2 | 按位或

只要有一个1就是1,常用于保留/合并

ABA | B
000
011
101
111

1.1.3 ^ 按位异或

不同才为 1,常用于去重

ABA ^ B
000
011
101
110

1.1.4 ~ 按位取反

0 变 1,1 变 0

A~A
01
10

1.2 判断 n 的第 x 位是 0 还是 1

本质是从二进制里读出某一位(位查询),可以使用位移 + 掩码:把目标搬到最后右边,再 &1 留末位判断,bit = (n >> x) & 1。

1.3 将第 x 位设为 1

本质就是位写入,可以通过 | 完成,n | (1 << x)。

1.4 将第 x 位设为 0

本质就是位清零,可以通过使 x 位与上0完成,n & ~(1 << x)。

1.5 提取最右侧的 1(lowbit)

本质是定位最低有效位 1  的全值,可以利用补码性质一次得到,lowbit = n & -n。

1.6 删除最右侧的 1

n-1 会把“最低 1 及其右侧”翻转;与回去即可清掉,n & (n-1)。

1.7 异或 ^ 的运算规律

举三个常见例子:

        (1) a ^ 0 = a

        (2) a ^ a = 0

        (3) a^b^c = 

2. 位 1 的个数

191. 位1的个数 - 力扣(LeetCode)

给定一个正整数 n,编写一个函数,获取一个正整数的二进制形式并返回其二进制表达式中 设置位 的个数(也被称为汉明重量)。

示例 1:

输入:n = 11
输出:3
解释:输入的二进制串 1011 中,共有 3 个设置位。

示例 2:

输入:n = 128
输出:1
解释:输入的二进制串 10000000 中,共有 1 个设置位。

示例 3:

输入:n = 2147483645
输出:30
解释:输入的二进制串 1111111111111111111111111111101 中,共有 30 个设置位。

2.1 题目解析

我们需要计算一个正整数 n 的二进制表示中有多少个“1”位。这被称为 汉明重量(Hamming Weight)。在实际中,二进制数的每一位如果是 1,就可以被称为“设置位”。

常规解法:

最直观的做法是将数字 n 转换为二进制字符串,然后遍历字符串,统计其中 1 的数量。比如:

  1. 将 n 转为二进制字符串;

  2. 遍历字符串,统计其中 1 的个数。
    这种做法直观易懂,但性能较差,因为每次转换为字符串时会有一定的开销。

这种解法的时间复杂度是 O(log n),因为将一个数字转为二进制需要 O(log n) 的时间。每次转换为二进制并统计 1 的个数需要额外的空间和操作,可能会引入不必要的计算。

思路转折:

为了提高效率,我们可以通过 位运算 来实现这一功能。特别是通过 n & (n - 1) 操作可以高效地减少 n 中的 1 的个数。每次执行这个操作都会清除最右边的一个 1,这就是我们要用的技巧。通过这种方式,我们可以在 O(log n) 时间内解决问题。

2.2 解法

通过利用 n & (n - 1) 操作来减少 n 中的 1 位数。每次这个操作将 n 中最右边的一个 1 清零,并且我们只需对这个操作重复进行直到 n 变为 0。通过计数这些操作次数,我们可以得到 n 中 1 的数量。

  • 每次 n & (n - 1) 操作会清除 n 中最右边的 1。

  • 所以,只需要执行这个操作若干次,每次将 n 中的一个 1 清除,直到 n 为 0,统计这些操作的次数即为汉明重量。

i)初始化一个计数器 ret,用于存储设置位的个数。

ii)使用 while 循环,直到 n 为 0:

  • 每次执行 n = n & (n - 1),去除最右边的 1。

  • 每执行一次操作,ret 增加 1。

iii)返回 ret,即二进制表示中 1 的个数。

2.3 代码实现

class Solution {public int hammingWeight(int n) {int ret = 0;// 当 n 不为 0 时,继续执行while (n > 0) {// 清除最右边的 1n = n & (n - 1);// 计数器加 1ret++;}return ret;}
}

3. 比特位计数

338. 比特位计数 - 力扣(LeetCode)

给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

示例 1:

输入:n = 2
输出:[0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10

示例 2:

输入:n = 5
输出:[0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101

3.1 题目解析

本题要求对于每个数字 i (0 <= i <= n),计算其二进制表示中 1 的个数,并将这些结果返回一个长度为 n + 1 的数组 ans。换句话说,给定一个整数 n,我们需要求出从 0 到 n 中每个数的二进制中 1 的数量。

常规解法:

一种直观的做法是逐个计算每个数字 i 的二进制形式,统计其中 1 的个数。例如:

  1. 遍历每个数字 i 从 0 到 n;

  2. 对于每个数字 i,转换为二进制表示,并统计 1 的个数。 这种方法比较直观,但是每次都需要进行二进制转换,效率较低,尤其是当 n 较大时,转换和计数会花费大量时间。

这种方法的时间复杂度是 O(n * log n),因为每个数字的二进制表示最多有 O(log n) 位,需要对每个数字执行一次二进制转换和计数。而当 n 非常大时,这种方法的效率可能不足以满足性能要求。

思路转折:

为了提高效率,我们可以使用 动态规划 或 优化的位运算方法。关键是利用 i >> 1 这种操作,因为每个数字 i 的二进制 1 的个数可以通过它的“高位部分”来推导。

  • ret[i] = ret[i >> 1] + (i & 1):这个公式的含义是:i >> 1 表示去掉 i 的最低位后剩余的数字,我们已经知道其二进制 1 的个数;(i & 1) 用来检查 i 的最低位是否为 1,如果是 1 就加 1,否则加 0。

通过这种方式,我们可以利用之前计算过的结果高效地推算出下一个结果,从而避免重复计算。

3.2 解法

通过动态规划的方式,使用递推公式 ret[i] = ret[i >> 1] + (i & 1) 来计算每个数字的二进制 1 的个数,其中:

  • i >> 1 表示数字 i 右移一位,去掉最低位

  • (i & 1) 检查 i 的最低位是否为 1。

这种方法通过复用之前计算的结果,避免了重复的二进制转换,极大提高了效率。

i)初始化一个长度为 n + 1 的数组 ret,用来存储从 0 到 n 每个数字的二进制中 1 的个数。

ii)从 i = 1 开始遍历到 n,使用公式 ret[i] = ret[i >> 1] + (i & 1) 来计算每个数字的二进制中 1 的个数。

iii)返回最终的 ret 数组。

3.3 代码实现

class Solution {public int[] countBits(int n) {int[] ret = new int[n + 1];  // 用于存储结果// 从 1 开始,因为 0 的汉明重量已知为 0for (int i = 1; i <= n; i++) {ret[i] = ret[i >> 1] + (i & 1);  // 右移一位并加上最低位的 1}return ret;}
}

4. 汉明距离

461. 汉明距离 - 力扣(LeetCode)

两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。

给你两个整数 x 和 y,计算并返回它们之间的汉明距离。

示例 1:

输入:x = 1, y = 4
输出:2
解释:
1   (0 0 0 1)
4   (0 1 0 0)↑   ↑
上面的箭头指出了对应二进制位不同的位置。

示例 2:

输入:x = 3, y = 1
输出:1

提示:

  • 0 <= x, y <= 231 - 1

4.1 题目解析

本题要求计算两个整数 x 和 y 之间的 汉明距离。汉明距离是指这两个数字对应二进制位不同的位置的个数。例如,如果两个数字的二进制表示不同,那么它们之间的汉明距离就是它们在二进制表示上不相同的位数。

常规解法:

最直观的做法是将两个数字 x 和 y 转换为二进制表示,逐位比较它们的差异。具体步骤如下:

  1. 将 x 和 y 转换为二进制字符串。

  2. 遍历这两个字符串,计算它们在相同位置上的字符是否不同,如果不同,则增加汉明距离。
    这种做法较为直接,但对于数字比较大的情况下,转化为二进制字符串并逐位比较会浪费时间和空间。

上述方法的时间复杂度是 O(log n),因为需要将数字转为二进制并逐位比较。然而,对于较大的数字来说,转换为字符串后再进行比较可能会涉及额外的内存分配,降低效率。

思路转折:

为了提高效率,可以通过位运算来解决这个问题。通过 异或(XOR) 操作,我们可以迅速找出 x 和 y 在二进制表示上不同的位置。

  • 异或操作:如果两个数字在某一位不同,则该位的结果为 1;如果相同,则该位的结果为 0。

  • 通过 x ^ y 我们可以得到一个新的数字,其中 1 表示两个数字在该位上不同,0 表示相同。

  • 之后,我们只需要统计这个异或结果中 1 的个数,即为它们之间的汉明距离。

4.2 解法

异或运算:通过 x ^ y,得到一个新数字,其中每个 1 表示 x 和 y 在该位不同

统计 1 的个数:通过位操作统计异或结果中 1 的个数,即为汉明距离。

i)计算 x ^ y,得到一个新的数 tmp,其中每个 1 表示 x 和 y 在该位不同。

ii)使用 tmp & 1 判断 tmp 的最低位是否为 1,如果是 1,则说明该位 x 和 y 不同,汉明距离增加 1。

iii)右移 tmp,继续检查剩余的位,直到 tmp 为 0。

iiii)返回最终的汉明距离。

4.3 代码实现

class Solution {public int hammingDistance(int x, int y) {int distance = 0;           // 汉明距离计数器int tmp = x ^ y;            // 计算 x 和 y 的异或结果while (tmp > 0) {           // 当 tmp 不为 0 时,继续统计不同的位distance += tmp & 1;    // 检查最低位是否为 1,如果是,增加汉明距离tmp >>= 1;              // 右移一位,继续检查}return distance;            // 返回最终汉明距离}
}

http://www.dtcms.com/a/342967.html

相关文章:

  • 【黑客技术零基础入门】硬核科普什么是HTMLHTML基本结构以及HTML基本使用(非常详细)零基础入门到精通,收藏这一篇就够了!
  • 轻量级加密的下一站:后量子、AI 与自动化验证
  • 【iOS】SDWebImage第三方库源码学习笔记
  • JupyterLab 安装(python3.10)
  • 大模型之原理篇——Transformer基础、分词器
  • 深度剖析:PCB 厚铜板铜厚检测,铜厚不足的连锁反应及检测手段
  • 性能测试中性能分析与调优学习大纲整理
  • C++中纯虚函数与普通虚函数的深度解析
  • 面试紧张情绪管理:如何保持冷静自信应对挑战
  • CLAUDE.md文件介绍(Claude Code核心配置文件,开始对话或执行任务时自动加载的上下文文件)
  • 工业大模型的应用场景
  • Ubuntu22.04设置共享文件夹
  • 2025年渗透测试面试题总结-25(题目+回答)
  • 数据库运维管理平台全面解析
  • opencv学习:图像边缘检测
  • # 重磅发布 | onecode 3.0.1 Base 源码正式开源:AI赋能的企业级开发框架
  • 算法训练营day58 图论⑧ 拓扑排序精讲、dijkstra(朴素版)精讲
  • 从零开始的Agent学习(二)-增加文档输出功能
  • 医疗信创新征程:常德二院全栈国产化项目引领行业变革
  • 审美积累 | 界面设计拆分 | Redesign Health - Services 医疗页面设计
  • 8.21网络编程——词典(未完成,有问题)
  • kotlin协程笔记-朱凯
  • C# 基本数据类型
  • 生信分析自学攻略 | R语言数据筛选和修改
  • 前端:文件直接在浏览器里下载
  • VMware ESXi 服务器暴露高危漏洞,中国1700余台面临勒索软件威胁
  • UE 虚幻引擎, unreal engine(1)概略介绍,安装本引擎,创建账户,打开 UE,创建项目,项目导入内容,尝试运行的添加第一人称游戏,
  • Vibe Coding v.s Prompt Engineering
  • 【Docker】在Ubuntu22.04上安装Docker
  • 漫谈《数字图像处理》之平滑