【优选算法】位运算

news/2024/11/29 5:34:38/

在这里插入图片描述

目录

  • 常见位运算总结
    • 1、基础位运算
    • 2、给一个数n,确定它的二进制位的第x位上是0还是1
    • 3、将一个数n的二进制位的第x位改成1
    • 4、将一个数n的二进制位的第x位改成0
    • 5、位图的思想
    • 6、提取一个数n的二进制位中最右侧的1
    • 7、将一个数n的二进制位中最右侧的1变为0
    • 8、位运算的优先级
    • 9、异或(^)运算的运算律
  • 一、[位1的个数](https://leetcode.cn/problems/number-of-1-bits/description/)
  • 二、[比特位计数](https://leetcode.cn/problems/counting-bits/description/)
  • 三、[汉明距离](https://leetcode.cn/problems/hamming-distance/description/)
  • 四、[只出现一次的数字](https://leetcode.cn/problems/single-number/description/)
  • 五、[只出现一次的数字 III](https://leetcode.cn/problems/single-number-iii/description/)
  • 六、[判定字符是否唯一](https://leetcode.cn/problems/is-unique-lcci/description/)
  • 七、[丢失的数字](https://leetcode.cn/problems/missing-number/description/)
  • 八、[两整数之和](https://leetcode.cn/problems/sum-of-two-integers/description/)
  • 九、[只出现一次的数字 II](https://leetcode.cn/problems/single-number-ii/description/)
  • 十、[消失的两个数字](https://leetcode.cn/problems/missing-two-lcci/description/)
  • 结尾

常见位运算总结

1、基础位运算

左移操作符 >> 、右移操作符 << 、按位取反 ~ ,这三个操作符我不做讲解。

接下来讲解3个操作符以及它使用方法对应的记忆方法

按位与:& 有0就是0
按位或:| 有1就是1
按位异或:^ 相同为0相异为1/无进位相加
在这里插入图片描述


2、给一个数n,确定它的二进制位的第x位上是0还是1

首先我们认为一个整数有32位、它最低位是0位,它的最高位为31位,那么就可以使用(n >> x)&1的操作来判断这个数的第x位是0还是1,因为n>>x能够将数字n上的第x位移动到第0位,1除了第0位上是1,其他位都是0,异或后结果只会出现第0位上为0/1其他位为0的情况,所以结果是0则数n二进制位的第x位上是0,是1则数n二进制位的第x位上是1。

在这里插入图片描述


3、将一个数n的二进制位的第x位改成1

首先我们认为一个整数有32位、它最低位是0位,它的最高位为31位,那么就可以使用n|=(1<<x)的操作将数字n的二进制位的第x位改成1。1<<x能够将1的第x位变为1,异或后无论n上的第x位上是0是1都会变为1。

在这里插入图片描述


4、将一个数n的二进制位的第x位改成0

首先我们认为一个整数有32位、它最低位是0位,它的最高位为31位,那么就可以使用n&=(~(1<<x))的操作将数字n的二进制位的第x位改成0。1<<x能够将1的第x位变为1,按位与后除了第x位上为0其他位上都为1,再与n按位与后,n中的第x位都会被0变为1,其他位都是与1按位与,则都不变。

在这里插入图片描述


5、位图的思想

位图的本质就是哈希表,我们在之前就学习过哈希表,哈希表很多情况下是数组,假设是一个int类型的数组,可以通过在数组中存储某些数组来表示某些意义,现在我们可以通过变量的比特位来表示某些信息,假设一个int类型的变量,一个int类型的变量有32位,其中的每一位存储的0/1都可以分别表示某种信息。

在这里插入图片描述


6、提取一个数n的二进制位中最右侧的1

首先我们认为一个整数有32位、它最低位是0位,它的最高位为31位,那么就可以使用n&-n的操作提取一个数n的二进制位中最右侧的1。这里的-n也就~n+1,-n能够将最右侧1的左侧所有二进制数字变成相反的,+1能将右侧所有二进制数字变为0,按位与后就只剩下最右侧的1。
在这里插入图片描述


7、将一个数n的二进制位中最右侧的1变为0

首先我们认为一个整数有32位、它最低位是0位,它的最高位为31位,那么就可以使用n&(n-1)的操作将一个数n的二进制位中最右侧的1变为0。-1能够将数字n最右侧1的左侧二进制数字变成相反的(包括它本身),按位与后右侧不变,左侧都不同则都变为0,就可将最右侧的1变为1。

在这里插入图片描述


8、位运算的优先级

位运算的优先级大家可以在其他文章中查看,这里建议大家能加括号就加括号。


9、异或(^)运算的运算律

  1. a^0 = a
  2. a^a = 0
  3. a^b^c = a^(b^c)

一、位1的个数

题目描述
在这里插入图片描述

思路讲解
在上面常见位运算总结中讲到了如何将一个数的二进制位中最右侧的1修改为0,我们只需要重复这个操作,并记录这个操作的次数,当这个数变为0以后,操作次数就是这个数二进制位中1的个数。

编写代码

class Solution {
public:int hammingWeight(int n) {int count = 0;while(n > 0){// 去掉最右侧的一n &= (n - 1);count++;}return count;}
};

二、比特位计数

题目描述
在这里插入图片描述

思路讲解
这题的思路与上一题的思路一致,只是上一题是获取一个数的二进制位中有多少个1,而本题是获取n个数的二进制位中有多少个1,本质上是一样的,这里不做过多讲解。

编写代码

class Solution {
public:int hammingWeight(int n) {int count = 0;while(n > 0){// 去掉最右侧的1n &= (n - 1);count++;}return count;}vector<int> countBits(int n) {vector<int> ans;for(int i = 0 ; i <= n ;i++)ans.push_back(hammingWeight(i));return ans;}
};

三、汉明距离

题目描述
在这里插入图片描述

思路讲解
两个整数之间的 汉明距离 指的是这两个数字对应二进制位不同的位置的数目。所以我们只需要将两个数每个对应的二进制位上的数字获取并对比,记录
二进制位不同的位置的数目即可,我们在上面讲到过可以使用(n >> x)&1的操作获取一个数的第x位上的二进制是0还是1。

编写代码

class Solution {
public:int hammingDistance(int x, int y) {int count = 0;for(int i = 0 ; i <= 31 ;i++){if(((x >> i) & 1) != (((y >> i) & 1)))count++;}return count;}
};

四、只出现一次的数字

题目描述
在这里插入图片描述

思路讲解
在上面异或运算的运算律中我们讲到过a^a=0a^0=a,本题中除了一个数只出现过一次,其他数都出现过两次,将所有的数异或在一起,出现过两次的数全部异或到一起就是0,出现过一次的数与0异或就是我们需要的结果。

编写代码

class Solution {
public:int singleNumber(vector<int>& nums) {int val = 0;for(auto ch : nums){val ^= ch;}return val;}
};

五、只出现一次的数字 III

题目描述
在这里插入图片描述
思路讲解

在上面异或运算的运算律中我们讲到过a^a=0a^0=a,本题中除了两个数只出现过一次,其他数都出现过两次,将所有的数异或在一起,就是两个只出现一次的数相异或的结果。两个数异或的结果的二进制位上有1就代表着两个数在当前位上一定是不同的,我们可以将两数异或结果上某一个1的位置标记,记为pos,将所以pos位上为1的数全部异或在一起,就能够得到其中一个答案,再将两数异或的结果与刚刚得到的一个答案异或,就能够得到另一个答案。

编写代码

class Solution {
public:vector<int> singleNumber(vector<int>& nums) {vector<int> v;v.resize(2 , 0);int xor1 = 0;// 将所有数异或,可以得到需要的两个数的异或for(auto x : nums){xor1 ^= x;}// 我们知道,异或后的二进制位上的 1,// 必定是两个数对应二进制位上的一个,且只有一个 // 那我们只需要将某一位上的1的位置记录下来// 并且将数组遍历一遍,将这个位置上为1的数全部异或就能得到第一个数// 再将第一步中两个数的异或值与第一个数异或就能得到第二个数int pos = 0;for(int i = 0 ; i < 32 ;i++){if( ((xor1 >> i) & 1 ) == 1 ){pos = i;break;}}for(int i = 0 ; i < nums.size() ; i++){if(((nums[i] >> pos) & 1) == 1){v[0] ^= nums[i];}}v[1] = xor1 ^ v[0];return v;}
};

六、判定字符是否唯一

题目描述
在这里插入图片描述

思路讲解
本题最简单的思路就是建立一个数组,将每个字母出现的次数记录下来,当有一个字符出现两次就返回false,但是这样需要花费4*26个字节,而使用位图则只需要4个字节,一个int类型的变量就有32个比特位,将26位小写字母对应到其中的32个比特位中,当遍历到一个字符的时候,就查看对应比特位上是0/1,如果是1就返回false,是0就继续遍历字符串。

本题还有一个优化方案就是雀巢原理,小写字母一共有26个,当字符串的长度超过26时,说明一定有一个字母是出现过两次的。

编写代码

class Solution {
public:bool isUnique(string astr) {// 优化 雀巢原理if(astr.size() > 26)return false;// 因为小写字母只有26个// 而int中有32个比特位// 那么这里使用位图来解决问题int tmp = 0;for(auto e : astr){if(((tmp >> (e - 'a')) & 1) == 1)return false;elsetmp |= (1 << (e - 'a'));}return true;}
};

七、丢失的数字

题目描述
在这里插入图片描述

思路讲解
本题最简单的思路就是建立一个大小为n的数组arr,遍历nums并在arr中标记,当nums遍历完后,再遍历arr查看哪个数字没有被标记就是答案,但是这个方法的缺点就是需要使用额外的空间复杂度。

还有可以使用高斯求和,得到0到n之间的数相加后的结果,减去nums中数组中所有数,就是本题的答案。

还可以使用位运算,上课讲到过a^a=0a^0=a,将0到n中所有的数异或,再与nums数组中所有的数异或,就能够得到本题的答案。使用位运算可以将本题转化为上面只出现一次的数字的那道题。

编写代码

class Solution {
public:int missingNumber(vector<int>& nums) {int ans = 0;int numsLen = nums.size();for(int i = 0 ; i <= numsLen ;i++)ans ^= i;for(auto e : nums)ans ^= e;return ans;}
};

八、两整数之和

题目描述
在这里插入图片描述

思路讲解

我们在记忆按位异或使用的时候,按位异或就是无进位相加,那么这里只缺少进位,进位我们可以通过按位与获得,但是需要注意的是获得的进位需要向左侧移动一位。我们将按位异或得到的无进位相加的结果记为tmp1,将按位与获得的进位记为tmp2,持续将tmp1与tmp2按位异或和按位与得到无进位相加与进位,只要当进位tmp2为0时,tmp1就是结果。

在这里插入图片描述

编写代码

class Solution {
public:int getSum(int a, int b) {int tmp1 = (a & b)<<1;  // 两数按位与后向右移动一位,代表着进位int ans = a ^ b;        // 两数异或代表无进位相加while(tmp1 != 0){int tmp2 = tmp1;    // 记录tmp1tmp1 = (tmp1 & ans)<<1; ans ^= tmp2;}return ans;}
};

九、只出现一次的数字 II

题目描述
在这里插入图片描述

思路讲解
题目中讲到了有一个数只出现过一次,其他的数都出现了三次,那么将所有数的二进制位罗列出来,那么将所有数对应每一位相加起来会出现两种情况:3n与3n+1,通过将3n与3n+1进行%3,就能得到0和1的结果,这里得到的1就是只出现过一次的数字对应比特位上的1,只需要将这些1组合到对应的比特位上,得到的数字就是结果。

同理给你一个整数数组 nums ,除某个元素仅出现一次外,其余每个元素都恰出现n次,都可以使用这个方法。

编写代码

class Solution {
public:int singleNumber(vector<int>& nums) {int sum = 0;       // 记录所有数字某个二进制位的和int num = 0;       // 记录答案for(int i = 0 ; i < 32 ; i++){for(int ch : nums){// 将第i个位置上的二进制数字取出来相加sum += ((ch >> i)&1);}if(sum % 3 != 0){num |= (1 << i);}sum = 0;}return num;}
};

十、消失的两个数字

题目描述
在这里插入图片描述

思路讲解
本道题就是上面只出现一次的数字III和丢失的数字两道题的结合,只需要找到丢失两个数的按位异或的结果就可以使用只出现一次的数字III中的思路,分别得到两个数是哪两个数,这里就不做讲解。

编写代码

class Solution {
public:vector<int> missingTwo(vector<int>& nums) {int tmp = 0;int numsLen = nums.size();for(int i = 1 ; i <= numsLen + 2; i++)tmp ^= i;for(auto e : nums)tmp ^= e;int lowbit = (tmp & -tmp);int ans1 = tmp;for(int i = 1 ; i <= numsLen + 2; i++)if((lowbit & i) == lowbit)ans1 ^= i;for(auto e : nums)if((lowbit & e) == lowbit)ans1 ^= e; int ans2 = (tmp ^ ans1);return {ans1,ans2};}
};

结尾

如果有什么建议和疑问,或是有什么错误,大家可以在评论区中提出。
希望大家以后也能和我一起进步!!🌹🌹
如果这篇文章对你有用的话,希望大家给一个三连支持一下!!🌹🌹

在这里插入图片描述


http://www.ppmy.cn/news/1550821.html

相关文章

springboot项目使用maven打包,第三方jar问题

springboot项目使用maven package打包为可执行jar后&#xff0c;第三方jar会被打包进去吗&#xff1f; 答案是肯定的。做了实验如下&#xff1a; 第三方jar的项目结构及jar包结构如下&#xff1a;&#xff08;该第三方jar采用的是maven工程&#xff0c;打包为普通jar&#xf…

基于DHCP,ACL的通信

该问题为华为的学习资料 1.首先把所有的PC机全部设置为DHCP 2.配置地址 3.ospf 4.dhcp 5.acl AR1 dhcp en interface GigabitEthernet0/0/0ip address 192.168.1.254 255.255.255.0 dhcp select global interface GigabitEthernet0/0/1ip address 10.1.12.1 255.255.255.…

华为新手机和支付宝碰一下 带来更便捷支付体验

支付正在变的更简单。 11月26日&#xff0c;华为新品发布会引起众多关注。发布会上&#xff0c;华为常务董事余承东专门提到&#xff0c;华为Mate 70和Mate X6折叠屏手机的“独门支付秘技”——“碰一下”&#xff0c;并且表示经过华为和支付宝的共同优化&#xff0c;使用“碰…

网络知识1-TCP/IP模型

从用户端到服务端&#xff0c;tcp/ip模型可分为应用层、传输层、网络层、网络接口层 以下使用寄快递为例进行解释 应用层职责&#xff1a; 只关注与为用户提供应用功能&#xff0c;如HTTP、FTP、telnet、DNS、SMTP等 &#xff0c;应用层的职责就像我们寄快递时将快递给快递员…

微信小程序蓝牙writeBLECharacteristicValue写入数据返回成功后,实际硬件内信息查询未存储?

问题&#xff1a;连接蓝牙后&#xff0c;调用小程序writeBLECharacteristicValue&#xff0c;返回传输数据成功&#xff0c;查询硬件响应发现没有存储进去&#xff1f; 解决&#xff1a;一直以为是这个write方法的问题&#xff0c;找了很多相关贴&#xff0c;后续进行硬件日志…

Java项目实战II基于SpringBoot的教学资料管理系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 在教育信息化的大背景下&#xff0c;教学资料的高效管…

操作系统 内存管理——针对实习面试

目录 操作系统 内存管理什么是虚拟内存&#xff1f;什么是物理内存&#xff1f;解释虚拟内存和物理内存的区别什么是分页式存储&#xff1f;什么是分段式存储&#xff1f;解释分页式存储和分段式存储的区别什么是内存碎片&#xff1f;描述几种常见的内存分配算法描述几种常见的…

三格电子—EtherNet IP转Modbus RTU网关

EtherNet/IP转Modbus RTU网关 SG-EIP-MOD-210 产品用途 SG-EIP-MOD-210网关可以实现将Modbus接口设备连接到 EtherNet/IP网络中。用户不需要了解具体的Modbus和 EtherNet/IP协议即可实现将Modbus设备挂载到 EtherNet/IP接口的PLC上&#xff0c;并和Modbus设备进行数据交互。拓…