算法02 二进制与位运算

二进制作为计算机底层数据的核心表示方式,其独特的位结构和运算规则在算法设计中有着广泛且关键的应用。以下从基础操作、算法技巧、数据结构、经典问题等多个维度,全面梳理二进制在算法中的应用:


 
一、基础位运算:算法的“原子操作”


 
二进制的核心优势在于位运算的高效性(时间复杂度通常为O(1)),常见位运算包括:
 
与(&):两个位都为1则为1,否则为0。常用于“保留指定位”(如 x & mask 保留mask中1对应的位)。

或(|):两个位有一个为1则为1,常用于“设置指定位为1”(如 x | mask 将mask中1对应的位设为1)。

异或(^):两个位不同则为1,相同则为0。特性: x ^ x = 0 , x ^ 0 = x ,可用于“交换变量”“找唯一出现奇数次的数”等。

左移(<<)
: x << k  等价于  x * 2^k (无溢出时),快速放大。

右移(>>): x >> k  等价于  x /2^k (整数除法),快速缩小。

取反(~):位反转(0变1,1变0),常用于构造掩码(如 ~0 是全1的二进制)。
 
这些操作是二进制应用的基础,几乎所有二进制相关算法都依赖它们。


 
二、状态压缩:用二进制表示“集合状态”


 
当问题需要表示“元素是否被选择”“状态是否激活”等集合信息时,二进制可将集合状态压缩为一个整数,大幅节省空间并简化操作。
 
典型场景:
 
1. 子集枚举
若有 n 个元素,每个子集可表示为一个 n 位二进制数(第 i 位为1表示元素 i 在子集中)。例如, n=3 时,二进制 101 表示子集 {0, 2} 。
枚举所有子集的代码可简化为:
python
   

for mask in range(0, 1 << n):  # 1<<n 即2^n,覆盖所有子集
    # mask的二进制表示即为一个子集
 

2. 动态规划中的状态压缩
例如旅行商问题(TSP):用 dp[mask][u] 表示“已访问的城市集合为 mask (二进制),当前在城市 u 时的最小距离”。其中 mask 的第 i 位为1表示城市 i 已访问。
状态转移依赖位运算: if not (mask & (1 << v)) (判断城市 v 是否未访问)。

3. 位掩码优化
例如“N皇后问题”中,用三个整数(列、主对角线、副对角线)的二进制表示当前禁止放置的位置,通过位运算快速判断合法性。


 
三、二进制特性:解决数学与计数问题


 
二进制的表示本身蕴含特殊规律,可用于优化数学问题的求解:
 
1. 判断2的幂
若 n 是2的幂(如2、4、8),则二进制表示为 100...0 ,满足  n & (n-1) == 0 (如 8(1000) & 7(0111) = 0 )。

2. 计算二进制中1的个数(位计数)
方法1:循环检查每一位( count += n & 1; n >>= 1 )。
方法2:Brian Kernighan算法(高效): while n: n &= n-1; count +=1 (每次清除最后一个1)。
应用:汉明距离(两数二进制不同位的数量,即 bin(x^y).count('1') )。

3. 二进制分解(拆分为2的幂之和)
任何整数 n 都可分解为 n = 2^a + 2^b + ... (如 5=4+1=2^2+2^0 )。
应用:贪心算法中,用最少的2的幂之和表示 n (直接取二进制中1的位置)。

4. 高低位分离与合并
例如将32位整数的高16位和低16位分离: high = (x >> 16) & 0xffff; low = x & 0xffff ,常用于哈希、加密等场景。


 
四、数据结构:基于二进制的高效设计


 
部分经典数据结构利用二进制的“分解性”(将问题拆分为2的幂次规模)实现高效操作:
 
1. 二进制索引树(Fenwick Tree,树状数组)
核心思想:将数组索引分解为二进制表示(如 index=5(101) 可分解为 4+1=2^2+2^0 ),通过树状结构存储前缀和,支持O(log n)的单点更新和前缀和查询。
应用:区间和、逆序对计数等。

2. 线段树的二进制优化
线段树的区间划分基于“二分”,本质是二进制分解(将区间拆分为2的幂次长度的子区间),其查询和更新效率(O(log n))依赖于二进制的快速拆分。

3. 二进制堆
堆的结构是完全二叉树,其父子节点索引关系(左子节点 2*i+1 ,右子节点 2*i+2 )本质是二进制的左移操作( i << 1 等价于 2*i ),因此堆的插入、删除操作可通过位运算快速定位节点。


 
五、算法优化:用位运算替代传统操作


 
二进制运算的高效性(硬件级支持)可优化算法的时间复杂度:
 
1. 替代算术运算

- 乘以/除以2的幂: x * 8 = x << 3 , x // 16 = x >> 4 (比乘法/除法快得多)。

- 判断奇偶: x & 1 == 1 (奇数),比 x % 2 更高效。

- 取模2的幂: x % 8 = x & 7 (因为 8=2^3 ,掩码 7=111 )。

2. 变量交换(无需临时变量)
利用异或特性: a ^= b; b ^= a; a ^= b (原理: a ^ b ^ a = b )。

3. 区间状态快速更新
例如用二进制表示“开关状态”,通过 mask ^ (1 << i) 快速翻转第 i 个开关的状态,比数组操作更简洁。


 
六、经典问题中的二进制应用


 
1. 子集和问题
当元素数量 n <= 20 时,可用二进制枚举所有子集( 2^20 ≈ 1e6 ),判断是否存在和为目标值的子集。

2. 最大异或对
给定数组,找一对数使其异或结果最大。解法:按二进制位从高到低构建前缀树(Trie),对每个数在树中找能使异或最大的数(每一位尽量取相反值)。

3. 位运算dp
例如“统计[0, n]中数字二进制不含连续1的个数”,用dp记录每一位的状态(是否为1),通过位转移避免连续1。

4. 格雷码生成
格雷码是相邻数二进制仅差1位的编码,生成公式: gray(n) = n ^ (n >> 1) ,利用二进制异或特性直接构造。
 
总结
 
二进制在算法中的应用核心是利用位运算的高效性和二进制表示的结构性,实现从基础操作到复杂问题的优化。无论是状态压缩、数据结构设计,还是数学问题求解,二进制都提供了简洁且高效的思路,是算法工程师必须掌握的基础工具。

七、实用的二进制运算技巧

n&(n-1)

将最低位的1置零

6&5 = 4 (110  101  ->100)

n&(-n)

保留最低位的1,其余位清零

6&-6 = 2 (110)

n|(n-1)

将最低位的1及其右边的位都置为1

6|5  =7 (110|101->111)

八、leetcode

九、算法讲解030【必备】异或运算的骚操作

算法讲解030【必备】异或运算的骚操作_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1LN411z7nu/?spm_id_from=333.1387.collection.video_card.click&vd_source=cdc2a34485eb016f95eae1a314b1a6201.异或:无进位相加

不同为1,相同为0

2.异或运算满足交换律和结合律

3.0^a=a      n^n=0

4.

1^0^1^0=1

1^0=1

5.异或运算交换两个数

a^=b;

b^=a;

a^=b;

6.不用任何判断语句和比较操作,返回两个数的最大值 

import mathdef get_max(a, b):return (a + b + math.fabs(a - b)) / 2
int max_with_xor(int a, int b) {int diff = a - b;// 获取符号位(对于32位整数)int sign = (diff >> 31) & 1;// 使用异或计算最大值return a ^ (sign ^ (a ^ b));
}

无溢出版

int max_with_xor_safe(int a, int b) {// 计算符号位:a和b符号不同时为1,相同时为0int sign_diff = ((a ^ b) >> 31) & 1;// 当a和b符号不同时:// - 若a为正,则a大;若a为负,则b大int result1 = (a >> 31 & 1) ? b : a;// 当a和b符号相同时:// 使用异或方法(此时a-b不会溢出)int diff = a - b;int sign = (diff >> 31) & 1;int result2 = a ^ (sign ^ (a ^ b));// 根据符号是否相同选择结果(利用异或的特性)return (sign_diff ? result1 : result2);
}

7.找到缺失的数字

原[0,1,2,4]

补全[0,1,2,3,4]

原的异或^补全的异或=缺失的数字

268. 丢失的数字 - 力扣(LeetCode)https://leetcode.cn/problems/missing-number/submissions/8.数组中一种数出现了奇数次,其他的数都出现了偶数次,返回出现了奇数次的数

阉割版

136. 只出现一次的数字 - 力扣(LeetCode)https://leetcode.cn/problems/single-number/submissions/654128520/9.找出数组中两个出现偶数次的数

先全部异或得到a^b

取出最右侧的1

之后树状数组也会用到

n&((~n)+1)=n&(-n)

Brian Kernighan算法

n&(n-1)

10.找唯一一个出现次数少于m次的数

看二进制的状态

11.补充:

计算一个数的二进制表示中 1 的个数

class Solution {
public:// 计算n的二进制表示中1的个数int hammingWeight(int n) {int count = 0;// 当n不为0时,继续循环while (n != 0) {// 清除最右边的1n &= n - 1;// 计数加1count++;}return count;}
};

其他方法

int hammingWeight(int n) {int count = 0;for (int i = 0; i < 32; i++) {// 检查第i位是否为1if ((n & (1 << i)) != 0) {count++;}}return count;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/95988.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/95988.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PAT 1071 Speech Patterns

题目大意是说给出一个文本&#xff0c;找出里面出现最多的单词&#xff0c;如果有多个单词出现次数一样多&#xff0c;则输出字典序最小的。 需要注意的是&#xff1a; 给出的文本字符串不仅有数字还有字母&#xff0c;还有一些特殊的字符&#xff0c;还有空格。 而单词是只包含…

CSS中的 :root 伪类

在CSS中&#xff0c;伪类是一种用于选择元素特定状态的选择器。:root 伪类专门用于选择文档的根元素&#xff08;在HTML中通常是<html>元素&#xff09;&#xff0c;它是CSS变量&#xff08;Custom Properties&#xff09;的理想载体&#xff0c;常用于定义全局样式变量&…

能源行业数字化转型:边缘计算网关在油田场景的深度应用

能源行业数字化转型&#xff1a;边缘计算网关在油田场景的深度应用能源行业是国民经济的支柱产业&#xff0c;而油田作为能源生产的重要基地&#xff0c;其数字化转型对于提高生产效率、降低能耗、减少碳排放具有重要意义。然而&#xff0c;油田往往地处偏远&#xff0c;油井分…

CAG缓存增强生成与RAG检索增强生成对比

深度定制 LLM 知识,除了 RAC &#xff0c;现在又有新技术假设有一份200页的产品手册,你想让 LLM 准确回答里面的相关问题,要实现这个目标,除了常用的检索增强生成技术 rep ,现在有了新思路,缓存增强生成 CAG &#xff0c;它是什么,何时使用.RAG检索增强是常规套路,CAG缓存增强是…

基于vue、node.js、express的网络教学系统设计与实现/基于vue、node.js、express的在线学习系统设计与实现

基于vue、node.js、express的网络教学系统设计与实现/基于vue、node.js、express的在线学习系统设计与实现

享元模式引发的关于ECS和对象池的思考记录

文章目录概念概述解决了什么区别与联系享元模式的某个例子的细节分析概念概述 ECS&#xff08;Entity-Component-System&#xff09; 1、Entity&#xff08;实体&#xff09;&#xff1a;唯一标识符。 2、Component&#xff08;组件&#xff09;&#xff1a;纯数据容器&#x…

STM32驱动SG90舵机全解析:从PWM原理到多舵机协同控制

一、SG90舵机核心特性 1.1 基本参数与选型 SG90作为​​微型舵机的代表​​,凭借其​​轻量化设计​​(仅9g)和​​高性价比​​,在机器人、智能小车和云台系统中广泛应用: ​​关键参数对比​​: ​​参数​​ 180定位舵机 360连续旋转舵机 ​​控制目标​​ 精确…

goland怎么取消自动删除未使用的包

1.settings-Go-Imports-取消勾选Optimize imports on the fly2.settings-Tools-取消勾选Optimize imports

halcon基于透视的可变形模型匹配

算子1&#xff0c;create_planar_uncalib_deformable_model_xld***基于平面未校准的轮廓模型算子2&#xff0c;find_planar_uncalib_deformable_model***查找平面未校准可变形模型算子3&#xff0c;projective_trans_contour_xld***将轮廓进行透视变换附加算子 算子4read_conto…

Flink Stream API - 源码开发需求描述

概述 本文介绍如何基于Flink源码进行二次开发&#xff0c;实现一个动态规则引擎系统。通过自定义算子和算子协调器&#xff0c;实现数据流的动态规则计算和协调管理。以此更好理解前面介绍的源码相关文章 项目需求 核心功能 实现一个动态规则引擎&#xff0c;具备以下特性&…

「 CentOS7 安装部署k8s」

一、Linux系统部署K8s还是非常便利的&#xff0c;只需要掌握Linux常用命令&#xff0c;便可以迅速部署&#xff0c;一起来学习一下吧1、运行以下命令更新系统并安装必要工具&#xff1a;yum update -y yum install -y yum-utils device-mapper-persistent-data lvm22、安装Dock…

Disbursement on Quarantine Policy(概率、逆元计算期望)

题目描述There is a train with n rows, and there are m seats per row. All seats are occupied. For some passengers, we know they are being infected with COVID-19 or not. However, for other passengers, we are not sure about their status, and we assume each of…

AI 在金融领域的落地案例

目录 引言 一、信贷风控&#xff1a;基于 LoRA 的 Qwen-7B 模型微调&#xff08;适配城商行审批场景&#xff09; 场景背景 核心代码 1. 环境依赖安装 2. 金融数据集加载与预处理&#xff08;城商行信贷数据&#xff09; 3. LoRA 微调 Qwen-7B 模型 4. 模型推理&#xf…

平衡二叉树的调整

平衡二叉树的定义平衡二叉树&#xff08;balanced binary tree&#xff09;&#xff0c;又称AVL树(Adelson-Velskii and Landis)。 一棵平衡二叉树或者是空树&#xff0c;或者是具有下列性质的二叉排序树&#xff1a;① 左子树与右子树的高度之差的绝对值小于等于1&#xff1b;…

深入解析:如何设计灵活且可维护的自定义消息机制

深入解析&#xff1a;如何设计灵活且可维护的自定义消息机制 引言 在现代软件开发中&#xff0c;组件间的通信机制至关重要。无论是前端框架中的组件交互&#xff0c;还是后端服务间的消息传递&#xff0c;一个良好的消息机制能显著提升代码的可维护性和扩展性。本文将深入探讨…

PostgreSQL——用户管理

PostgreSQL用户管理一、组角色管理1.1、创建组角色1.2、查看和修改组角色1.3、删除组角色二、角色的各种权限2.1、LOGIN&#xff08;登录&#xff09;2.2、SUPERUSER&#xff08;超级用户&#xff09;3.3、CREATEDB&#xff08;创建数据库&#xff09;3.4、CREATEROLE&#xff…

东软8位MCU使用问题总结

简介用的单片机为ES7P7021&#xff0c;采用8位RISC内核&#xff0c;2KB的FLASH&#xff0c;128bit的RAM。编译器使用东软提供的iDesigner&#xff0c;开发过程中编译器和单片机有一些地方使用时需要注意下。1.RAMclear()函数注意问题/****************************************…

深度学习在订单簿分析与短期价格预测中的应用探索

一、订单簿数据特性及预处理 1.1 订单簿数据结构解析 在金融交易领域&#xff0c;订单簿是市场微观结构的集中体现&#xff0c;它记录了不同价格水平的买卖订单信息。一个典型的订单簿由多个层级组成&#xff0c;每个层级包含特定价格上的买单和卖单数量。例如&#xff0c;在某…

Hashmap源码

目录 HashMap底层原理 JDK1.8及以后底层结构为&#xff1a;数组链表红黑树 默认参数 扩容机制 数组 链表 红黑树 HashMap为什么用红黑树不用B树 HashMap什么时候扩容 HashMap的长度为什么是 2的 N 次方 HashMap底层原理 JDK1.8及以后底层结构为&#xff1a;数组链表红…

【JAVA 字符串常量池、new String的存储机制、==与equals的区别,以及字符串重新赋值时的指向变化】

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 提示&#xff1a;写完文章后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录系列文章目录代码原理解错误逻辑理解理解与修正&#xff1a…