【优选算法篇】:深入浅出位运算--性能优化的利器

embedded/2025/1/13 12:15:40/

✨感谢您阅读本篇文章,文章内容是个人学习笔记的整理,如果哪里有误的话还请您指正噢✨
✨ 个人主页:余辉zmh–CSDN博客
✨ 文章所属专栏:优选算法篇–CSDN博客

在这里插入图片描述

文章目录

  • 一.位运算
    • 一.位运算概述
    • 二.常见的位运算操作符
    • 三.常见的位运算使用场景
  • 二.例题
    • 1.判断字符是否唯一
    • 2.丢失的数字
    • 3.两整数之和
    • 4.只出现一次的数字||
    • 5.只出现一次的数字|||
    • 6.消失的两个数字

一.位运算

一.位运算概述

位运算(Bitwise operation)是直接对整数在内存中的二进制位进行操作的运算。在计算机编程中,位运算非常高效,因为它们直接在二进制层面上操作数据,能够以较少的操作实现复杂的逻辑。下面是几种常用的位运算符号讲解。

二.常见的位运算操作符

  1. 按位与(&)

    • 规则
      • 对两个整数对应的二进制位进行操作,如果对应的二进制位都为1,则结果位为1,否则为0。
    • 示例
      • 假设我们有整数5(二进制为0101)和3(二进制为0011)。
      • 5 & 3的计算过程为:
        • 0101
        • &0011

        • 0001(结果为1)
    • 应用场景
      • 常用于掩码操作。例如,要判断一个整数的某一位是否为1,可以将该整数与一个只有对应位为1的掩码进行按位与操作。
  2. 按位或(|)

    • 规则
      • 对两个整数对应的二进制位进行操作,如果对应的二进制位中有一个为1,则结果位为1。
    • 示例
      • 对于整数5(0101)和3(0011)。
      • 5 | 3的计算过程为:
        • 0101
        • |0011

        • 0111(结果为7)
    • 应用场景
      • 可以用于设置某些位的值。例如,要将一个整数的某几位设置为1,可以将该整数与一个只有对应位为1的数进行按位或操作。
  3. 按位异或(^)

    • 规则
      • 对两个整数对应的二进制位进行操作,如果对应的二进制位不同,则结果位为1,相同则为0。
    • 示例
      • 对于整数5(0101)和3(0011)。
      • 5 ^ 3的计算过程为:
        • 0101
        • ^0011

        • 0110(结果为6)
    • 应用场景
      • 常用于加密算法中的简单加密和解密操作,因为一个数与另一个数进行两次异或操作会得到原数。
  4. 按位取反(~)

    • 规则
      • 对一个整数的二进制位进行取反操作,即0变为1,1变为0。
    • 示例
      • 对于整数5(0101)。
      • ~5的计算过程为:
        • 0101取反后为1010(结果为 - 6,因为在有符号数的表示中,取反后会涉及到补码等概念,在8位二进制表示下,1010表示 - 6)
    • 应用场景
      • 在一些底层的逻辑判断和数据处理中,用于反转数据的某些特性。
  5. 左移(<<)

    • 规则
      • 将一个整数的二进制位向左移动指定的位数,右边空出的位用0填充。
    • 示例
      • 对于整数5(0101),5 << 2表示将5的二进制位向左移动2位。
      • 0101 << 2后变为010100(结果为20,因为左移n位相当于乘以2的n次方,这里5×2² = 20)
    • 应用场景
      • 常用于快速乘以2的幂次方的计算,在优化算法中经常用到。
  6. 右移(>>)

    • 规则

      • 将一个整数的二进制位向右移动指定的位数。如果是无符号数,左边空出的位用0填充;如果是有符号数,根据不同的编程语言和机器,可能是用符号位填充(算术右移)或者用0填充(逻辑右移)。
    • 示例

      • 对于整数12(1100),12 >> 1表示将12的二进制向右移1位。

      • 算术右移(有符号数):

        1100>>1变为1110(结果为-6,因为对于有符号数右移后要保持不变,原数12(假定位8位有符号数二进制表示为1110,符号位为1表示负数,将数值部分右移1位表示负数,将数值部分右移1位后得到1110,在补码表示下为-6)。

      • 逻辑右移:

        1100>>1变为0110(结果为6,逻辑右移是简单的将二进制位右移,左边补0)。

    • 应用场景

      • 常用于快速除以2的幂次方的计算呢,不过对于有符号数的算术右移要注意符号相关的问题。

三.常见的位运算使用场景

在这里插入图片描述

二.例题

1.判断字符是否唯一

题目

在这里插入图片描述

算法原理

利用位图的思想,一个整型有32位,正好可以存放26个字母,一位对应一个字母。

计算每个字母对应的位置,再将该位置标记为1,通过左移即可实现找到对应的位置。

如果该位置已经标记为1时,说明存在重复元素。

这里有一个小的优化,因为每个字母只能出现一次,所以字符串最大长度只能为26,如果字符串长度大于26时,即可直接返回false

代码实现

bool isUnique(string astr){//鸽巢原理优化if(astr.length()>26){return false;}//位图思想int bitmap = 0;for(auto ch : astr){//先求出字符所对应的位置下标int i = ch - 'a';//如果当前字符的位置为一说明字符重复if((bitmap>>i)&1==1){return false;}bitmap |= (1 << i);}return true;
} 

2.丢失的数字

题目

在这里插入图片描述

算法原理

根据异或的特点,相同为0,相异为1,将丢失数字的数组和没有丢失数字的原数组中所有的值全部异或即可找到丢失的数字

代码实现

int missingNumber(vector<int>& nums){//位运算int ans = nums[0];for (int i = 1; i < nums.size();i++){ans ^= nums[i];}for (int i = 0; i < nums.size() + 1;i++){ans ^= i;}return ans;
}

3.两整数之和

题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

//371.两整数之和
int getSum(int a, int b){while(b){int cur=a;a ^= b;b &= cur;b <<= 1;}return a;
}

4.只出现一次的数字||

题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

int singleNumber(vector<int>& nums){int ret = 0;for (int i = 0; i < 32;i++){int sum = 0;//求出数组中每个数的第i位之和for(auto num : nums){if((num>>i)&1==1){sum++;}}//求出只出现一次数字的第i位是1还是0sum %= 3;//修改ret的第i位if(sum==1){ret |= (1 << i);}}return ret;
}

5.只出现一次的数字|||

题目

在这里插入图片描述

算法原理

在这里插入图片描述

代码实现

vector<int> singleNumber(vector<int>& nums) {int tmp=0;for(auto num : nums){tmp^=num;}int mapbit=0;for(int i=0;i<32;i++){if(((tmp>>i)&1)==1){mapbit=i;break;}}int ans1=0,ans2=0;for(auto num : nums){if(((num>>mapbit)&1)==1){ans1^=num;}else{ans2^=num;}}return {ans1,ans2};
}

6.消失的两个数字

题目

在这里插入图片描述

算法原理
这道题其实就是前面两种题型的综合,丢失的数字+只出现一次的数字|||。
具体的算法原理就不再讲解,可以直接看代码实现来理解。

代码实现

vector<int> missingTwo(vector<int>& nums){//1.将当前数组和没有消失的两个数字的原数组全部异或int tmp = 0;for (auto num : nums){tmp ^= num;}for (int i = 1; i <= nums.size() + 2;i++){tmp ^= i;}//2.找到异或后的值哪一位为1int mapbit = 0;for (int i = 0;i<32;i++){if(((tmp>>i)&1)==1){mapbit = i;break;}}//3.根据异或后的值哪一位为1将两个数组中的所有值划分成两个,两个消失的数字分别在其中一个int ans1 = 0, ans2 = 0;for (auto num : nums){if(((num>>mapbit)&1)==1){ans1 ^= num;}else{ans2 ^= num;}}for (int i = 1; i <= nums.size() + 2; i++){if(((i>>mapbit)&1)==1){ans1 ^= i;}else{ans2 ^= i;}}return {ans1, ans2};
}

以上就是关于位运算算法的讲解,如果哪里有错的话,可以在评论区指正,也欢迎大家一起讨论学习,如果对你的学习有帮助的话,点点赞关注支持一下吧!!!
在这里插入图片描述


http://www.ppmy.cn/embedded/153559.html

相关文章

3. 使用springboot做一个音乐播放器软件项目【封装项目使用的工具类】

上一章文章 我们做了 音乐播放器这个项目的 框架搭建和一些基础配置文件。 参考网址&#xff1a; https://blog.csdn.net/Drug_/article/details/145044096 这篇文章我们来分享一些 项目中用到的一些工具类。 一般项目里 我会创建一个 utils 文件夹 来存放 项目中常用的工具类…

Rust 生命周期

Rust 生命周期 引言 Rust 是一种系统编程语言,以其内存安全、并发性和高性能而闻名。在 Rust 中,生命周期是一个核心概念,用于确保引用的有效性,从而防止内存安全问题。本文将深入探讨 Rust 的生命周期,包括其工作原理、使用场景以及最佳实践。 生命周期基础 什么是生…

UnityDots学习(三)

此篇记录Dots使用的步骤。 Demo逻辑是在场景内创建2000个物体。1000个是搜索&#xff0c;1000是被搜索的目标。 每个物体都随机朝某个方向移动。 在Update里。1000个搜索者会对1000被搜索的目标进行遍历查找到哪个目标离他最近&#xff0c;并且画出连线。 逻辑如下&#xf…

《分布式光纤测温:解锁楼宇安全的 “高精度密码”》

在楼宇建筑中&#xff0c;因其内部空间庞大&#xff0c;各类电器设施众多&#xff0c;如何以一种既高效又稳定&#xff0c;兼具低成本与高覆盖特性的方式&#xff0c;为那些关键线路节点开展温度监测&#xff0c;是目前在安全监测领域一项重点研究项目&#xff0c;而无锡布里渊…

QT 端口扫描附加功能实现 端口扫描5

上篇QT 下拉菜单设置参数 起始端口/结束端口/线程数量 端口扫描4-CSDN博客 在扫描结束后设置Scan按钮为可用&#xff0c;并提示扫描完成 在 MainWindow 类中添加一个成员变量来跟踪正在进行的扫描任务数量&#xff1a; 在 MainWindow 的构造函数中初始化 activeScanTasks&…

深入理解 Java 设计模式之策略模式

一、引言 在 Java 编程的世界里&#xff0c;设计模式就如同建筑师手中的蓝图&#xff0c;能够帮助我们构建出更加健壮、灵活且易于维护的代码结构。而策略模式作为一种经典的行为型设计模式&#xff0c;在诸多实际开发场景中都发挥着至关重要的作用。它能够让算法的定义与使用…

物联网无线芯片模组方案,设备智能化交互升级,ESP32-C3控制应用

无线交互技术的核心在于实现设备之间的无缝连接和数据传输。在智能家居系统中&#xff0c;各种智能设备如智能灯泡、智能插座、智能门锁等&#xff0c;都通过无线网络相互连接&#xff0c;形成一个互联互通的生态。 用户可以通过语音助手、手机APP或其他智能终端&#xff0c;远…

每日一题(二):判断一个字符串是否是另一个字符串的排列

一、题目 实现一个算法来识别一个字符串str2是否是另一个字符串str1的排列。 排列的解释如下&#xff1a;如果将str1的字符拆分开&#xff0c;重新排列后再拼接起来&#xff0c;能够得到str2&#xff0c;那么就说字符串str2是字符串str1的排列。 要求&#xff1a;不忽略大小写。…