【刷题】一篇文章搞定“位运算”

news/2024/11/13 9:45:56/

在这里插入图片描述
只要春天不死,就有迎春的花朵年年岁岁开放,生命讲涅槃,生生不息,并会以另一种形式永存。 – 路遥 《平凡的世界》

(◦′ᆺ‵◦) ♬° ✧❥✧¸.•¨✧♡✧ ℒℴѵℯ ✧♡✧¨•.❥
(◦′ᆺ‵◦) ♬° ✧❥✧¸.•¨✧♡✧ ℒℴѵℯ ✧♡✧¨•.❥
(◦′ᆺ‵◦) ♬° ✧❥✧¸.•¨✧♡✧ ℒℴѵℯ ✧♡✧¨•.❥


一篇文章搞定“位运算”

  • 1 前言
  • 2 位运算
  • 3 基础题目
  • 4 进阶题目
    • 4.1 Leetcode 260. 只出现一次的数字 III
    • 4.2 面试题 01.01. 判定字符是否唯一
    • 4.3 Leetcode 268. 丢失的数字
    • 4.4 Leetcode 371. 两整数之和
    • 4.5 Leetcode 137. 只出现一次的数字 II
  • 4 精通题目
    • 面试题 17.19. 消失的两个数字
  • Thanks♪(・ω・)ノ谢谢阅读!!!
  • 下一篇文章见!!!

1 前言

面试中经常会出现一类问题:它们看起来并不复杂,内容也很容易理解,但是它们往往带有一个额外的挑战条件——不允许使用额外的空间,或者说空间复杂度必须保持在O(1)。这类问题通常是为了考察应聘者对算法的深入理解以及对编程语言的掌握程度。

如果涉及到数组或者运算,经常就需要使用位运算来巧妙的解决这些问题。那么接下来我们来学习这个算法

2 位运算

我们熟知的位运算以下几种:

  1. & 按位或 :有 0 就为 0
  2. | 按位与 :有 1 就为 1
  3. ^ 按位异或 :相同为 0 ,不同为 1 / 无进位相加
  4. ~ 按位取反 :0 变 1 ,1 变 0
  5. << 向左移动 : 把二进制的每一位依次向左移动,右边补0
  6. >> 向右移动 : 把二进制的每一位依次向右移动,左边补0
  7. - 取负:先按位取反,然后在加1 。以最右侧的 1 为分割,左边的区域全部变成相反的 ,右边都变成 0
  8. 注意 一定一定要加上括号,位运算的优先级比较复杂。

通过这四种基础的位运算我们可以衍生出一些常用公式:

  • 判断一个数 x 的第 n 位是 0 / 1 : (x << n ) & 1 ,计算得到 1 那么第 n 位就是 1 ,反之是 0 。
  • 将一个数 x 的第 n 位修改为 1 : x |= (1 << n) ,直接就修改了
  • 将一个数 x 的第 n 位修改为 0 : x & ~(1 << n) ,这个比较复杂,(1 << n)会得到...00100...,按位取反后变成...11011...,然后按位或就可以不改变其他位置,就将第 n 位修改为 0了
  • 提取一个数 x 二进制的最右侧的 1 (lowbit):x & -x ,首先-x 会将x先按位取反,然后在加1。比如x是11010,那么-x就是 ->00101 -> 00110 。然后 x & -x 就会得到00010。十分巧妙!
  • 干掉一个数 x 最右侧的1 : x & x - 1x - 1这个操作就将最右侧的1左边不变,右边变成相反的。

另外提一个重要的东西:位图。通过比特位来进行判断是否存在。

3 基础题目

Leetcode 191. 位1的个数
Leetcode 338. 比特位计数
Leetcode 461. 汉明距离
Leetcode 136. 只出现一次的数字
这些题目比较基础,读懂题目,然后使用合理的位运算就可以了!

4 进阶题目

4.1 Leetcode 260. 只出现一次的数字 III

链接:Leetcode 260. 只出现一次的数字 III

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

数组里面有两个元素只出现一次,其余出现两次,那么我们需要找到这两个元素

算法思路
首先因为其余元素都是出现两次,那么我们直接进行一次遍历,并依次进行按位异或操作。就会得到一个结果,这个结果是只出现两次的元素的异或和。

又因为这两个元素是不同的,所以异或和必然有一位是 1 ,那么就以这个1来将所有元素进行分类。这样两个不同的元素就必然处于两个不同的组之中,那么就是找只出现一次的数字了!!!

    vector<int> singleNumber(vector<int>& nums) {//先得到异或和unsigned int  tmp = 0;for(auto s :nums){tmp ^= s;}//因为要取出一个 1 不妨就取最右边的 1 int lowbit = tmp & -tmp;//进行分类分析vector<int> ans(2);//容器的0 1 分别进行两组的异或处理for(auto s :nums)ans[(s & lowbit) != 0] ^= s;return ans;}

提交:过啦!!!

4.2 面试题 01.01. 判定字符是否唯一

链接:面试题 01.01. 判定字符是否唯一
题目描述
在这里插入图片描述

题目非常好理解!

算法思路
这道题有很多解法:哈希表 , 双指针 , 位运算
我们采取位运算的位图来解决问题,让面试官眼前一亮。位图其实就是简略的哈希表(但是运算更快),我们进行储存的时候需要将1向左移动对应的距离,这个距离是独一无二的ch - 'a'

    bool isUnique(string astr) {//抽屉原理优化if(astr.size() > 26 ) return false;//位图int map = 0;//遍历进行位图的读取for( auto ch : astr){//位图的位置如果是 1 ,那么就说明已经有该字母了if(map & ( 1 << (ch - 'a'))) return false;//反正位图该位置变为 1 else map |= ( 1 << (ch - 'a'));}return true;}

提交: 过啦!!!

4.3 Leetcode 268. 丢失的数字

链接:268. 丢失的数字
题目描述
在这里插入图片描述

题目很好理解!

算法思路
这道题也有很多算法:哈希表,数学方法,位运算
这里也是采取位运算的方法,我们将[0 , n]的所有元素都进行按位异或。然后再把数组中的元素进行按位异或。得到的两个异或和再进行一次异或,就可以得到没有出现的元素了!因为只有这个元素是单身狗!

    int missingNumber(vector<int>& nums) {int n1 = 0 , n2 = 0 ;//一起处理,效率更高for(int i = 1 ; i <= nums.size() ; i++ ) {n1 ^= i;n2 ^= nums[i - 1];}   return n1 ^ n2;}

提交:过啦!!!

4.4 Leetcode 371. 两整数之和

链接 :371. 两整数之和
题目描述
在这里插入图片描述

题目一如既往的好理解!

算法思路
这道题还是使用位运算奥:
那么如何进行呢???
通过这两个法宝就可以:

  • ^ 按位异或 :相同为 0 ,不同为 1 / 无进位相加
  • & 按位或 :有 0 就为 0 -> 因为都为 1 才得 1 所以可以判断是否需要进位
  1. 首先按位异或得到没有进位的数 b1
  2. 然后按位或 在向左移动 一位得到进位 a1
  3. 在把a1 , b1重复 1 - 2直到没有进位为止!
    int getSum(int a, int b) {//位运算while(a){int a1 = 0, b1 = 0;b1 = a ^ b ;  //无进位相加a1 = (a & b) << 1;//进位//更新数值a = a1 , b = b1;} return b;}

4.5 Leetcode 137. 只出现一次的数字 II

链接:137. 只出现一次的数字 II
题目描述
在这里插入图片描述

题目很好理解!

算法思路
这个与之前出现的只出现一次的数字不同,其他数字出现了3次。这要如何进行?
首先每个int类型数字都是由比特位组合成的:
那么我们就来看每个比特位相加会发生什么:
在这里插入图片描述
发现了吗? 无论什么情况,该比特位的数字相加完再余上 3 就变成了只出现一次的数字对应的比特位!!!
那么我们只要报每个比特位都进行如下操作就可以了:

    int singleNumber(vector<int>& nums) {//位运算int ans = 0 ;//答案//开始遍历每一位比特位for(int i = 0 ; i < 32 ;i++ ){int bit = 0;//把每个元素的该位都进行相加for(auto s : nums)bit += (s >> i) & 1;//除3得到的余数就是该位的结果bit %= 3;ans |= (bit << i);}        return ans;}

提交:过啦!!!

4 精通题目

面试题 17.19. 消失的两个数字

链接:面试题 17.19. 消失的两个数字
题目描述
在这里插入图片描述

这是一道困难题,但是在经过了上面的题目后,我们就能发现这道题其实超级简单

算法思路
首先这道题是要求我们找到[1 , N]中缺少的两个数字,那么其实就是:
丢失的数字 + 只出现一次的数字 III
为什么呢?
来看我们把数组的元素当做一个整体 sum
那么[1 , n]的元素相当于 sum + a + b。是不是这样???
分析到这一步就简单了,按照 丢失的数字 + 只出现一次的数字 III就ok了:

    vector<int> missingTwo(vector<int>& nums) {//位运算//[0 , n] 进行按位异或//数组元素进行按位异或//他们再进行按位异或int tmp = 0;for(int i = 1 ; i <= nums.size() + 2 ; i++)tmp ^= i;for(auto x:nums)tmp ^= x;//会得到消失两个数字的按位异或结果//这两个数字是不同的//所以取出最右边一位//分别进行按位异或,就可以得到对应的数字int lowbit = tmp & -tmp;vector<int> ans(2);for(int i = 1 ; i <= nums.size() + 2 ; i++)ans[(lowbit & i) != 0] ^= i;for(auto x:nums)ans[(lowbit & x) != 0] ^= x;return ans;}

Thanks♪(・ω・)ノ谢谢阅读!!!

下一篇文章见!!!


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

相关文章

代码大师的工具箱:现代软件开发利器

✨✨ 欢迎大家来访Srlua的博文&#xff08;づ&#xffe3;3&#xffe3;&#xff09;づ╭❤&#xff5e;✨✨ &#x1f31f;&#x1f31f; 欢迎各位亲爱的读者&#xff0c;感谢你们抽出宝贵的时间来阅读我的文章。 我是Srlua小谢&#xff0c;在这里我会分享我的知识和经验。&am…

漫威争锋Marvel Rivals怎么搜索 锁区怎么搜 游戏搜不到怎么办

即将问世的《漫威争锋》&#xff08;Marvel Rivals&#xff09;作为一款万众期待的PvP射击游戏新星&#xff0c;荣耀携手漫威官方网站共同推出。定档5月11日清晨9时&#xff0c;封闭Alpha测试阶段将正式揭开序幕&#xff0c;持续时间长达十天之久。在此首轮测试窗口&#xff0c…

生成ssh来连接git

生成SSH密钥&#xff1a; 打开你的命令行终端&#xff08;如Windows的CMD、PowerShell&#xff0c;或者Linux/Mac的Terminal&#xff09;。 运行以下命令来生成SSH密钥对&#xff08;私钥和公钥&#xff09;&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexampl…

Spring Boot集成Druid快速入门Demo

1.什么是Druid&#xff1f; Druid连接池是阿里巴巴开源的数据库连接池项目。Druid连接池为监控而生&#xff0c;内置强大的监控功能&#xff0c;监控特性不影响性能。功能强大&#xff0c;能防SQL注入&#xff0c;内置Loging能诊断Hack应用行为。 2.mysql环境搭建 第一个mysql数…

Gartner发布准备应对勒索软件攻击指南:勒索软件攻击的三个阶段及其防御生命周期

攻击者改变了策略&#xff0c;在某些情况下转向勒索软件。安全和风险管理领导者必须通过提高检测和预防能力来为勒索软件攻击做好准备&#xff0c;同时还要改进其事后应对策略。 主要发现 勒索软件&#xff08;无加密的数据盗窃攻击&#xff09;是攻击者越来越多地使用的策略。…

机器人系统ros2内部接口介绍

内部 ROS 接口是公共 C API &#xff0c;供创建客户端库或添加新的底层中间件的开发人员使用&#xff0c;但不适合典型 ROS 用户使用。 ROS客户端库提供大多数 ROS 用户熟悉的面向用户的API&#xff0c;并且可能采用多种编程语言。 内部API架构概述 内部接口主要有两个&#x…

数据分析师方差分析,单因素方差分析、多因素方差分析、协方差分析和重复测量方差分析,医学数据分析spss

单因素方差分析、多因素方差分析、协方差分析和重复测量方差分析在统计学中各有其特定的适用场景。 单因素方差分析&#xff08;One-way ANOVA&#xff09;&#xff1a;适用于检验单因素水平下的一个或多个独立因变量均值是否存在显著差异&#xff0c;即检验单因素各个水平的值…