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

【LeetCode热题100】位运算

这篇博客先介绍了常见位运算操作,然后记录了关于位运算的几道题,包括判定字符是否唯一、丢失的数字、两整数之和、只出现一次的数字2、消失的两个数字。

在这一部分,我们不妨先来总结一下常见位运算操作:

1.基础位运算

>>是右移操作,<<是左移操作,~是按位取反,&是有0就是0,|是有1就是1,^有两种记忆方法1)相同为0,相异为1 2)无进位相加

2.给一个数n,确定它的二进制表示表示中的第x位是0还是1        

我们约定,二进制的最右边为第0位,最左边为第31位,操作是(n>>x)&1,如果结果为0,那么第x位就是0,否则为1。

3.将一个数n的二进制表示的第x位修改成1

也就是第x位改为1,其它位保持不变,操作是 n  |=  (1<<x)

4.将一个数n的二进制表示的第x位修改成0

操作是  n &= (~(1<<x)) 

5.位图的思想

上面的2、3、4就是为位图来服务的,位图的本质是哈希表,让一个int的32个位的0/1来记录信息,利用2、3、4可以查看和修改位图。

6.提取一个数(n)二进制表示中最右侧的1(lowbit操作)

先来说结果,操作是  n&-n。我们需要先来看一下-n的本质:

-n的本质是将最右侧的1,左边的区域全部变成相反,此时相&后,左边区域全部变成0,右边区域本来就是0,所以&完之后只剩下最右侧的1。

7.干掉一个数(n)二进制表示中最右侧的1

先来说结果,操作是  n&(n-1) ,我们需要看一下n-1的本质:让最右侧及其右边全变成相反,左侧不变,这样相&之后,左侧不变,右侧全部变成0,这就把最右侧的1干掉了。

8.位运算的优先级

能加括号就加括号。

利用上面这几条,我们就可以解决LeetCode中的191、338、461这三道题了,

9.异或^运算的运算律

1) a^a = 0(消消乐)

2) a^0 = a

3)a^b^c = a^c^b

class Solution {
public:bool isUnique(string astr) {int bitmap = 0;for(auto e:astr){int pos = e - 'a';if((bitmap>>pos) & 1) return false;bitmap |= (1<<pos);}return true;}
};

题目分析:这道题有很多种解法,这里我们学习两种方法:哈希表和位图。第一种,使用哈希表,遍历整个字符串,将字符串中的每个字符依次放到哈希表中并判断条件,这种方法的时间复杂度和空间复杂度都是O(N)。第二种,使用位图,使用一个int位图,0位表示'a',1位表示'b',依次类推,因此只需要用到0~25位,遍历整个字符串,修改对应的bit,bit位为0表示之前没遇到这个字符,bit位为0表示之前遇到过这个字符。

此外,我们还可以使用鸽巢原理(抽屉原理)进行优化,如果字符长度大于26,说明肯定有重复字符,直接返回false。

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

题目分析:这道题我们还是有很多思路的,包括哈希表、求和公式、异或运算。第一种,哈希表,将数组中所有数字依次放到哈希表中,然后看哈希表中缺失哪个数字。第二种,求和公式,计算出0~n之和,然后减去数组中的每个元素,剩下的就是缺失的元素。第三种,异或运算,将数组中每一个元素都异或到一起,然后再异或0~n中的每一个元素,结果就是缺失的数字。

class Solution {
public:int getSum(int a, int b) {while(b != 0){int x = a^b;// x是无进位相加的结果int carry = (a&b)<<1;// carry 是进位a = x;b = carry;}return a;}
};

题目分析:这种直接用加法求和,大概率是用位运算操作,我们画图来看一下具体方法,主要想法是,a^b是无进位相加,a&b<<1可以表示进位,当进位为0时,循环结束。

class Solution {
public:int singleNumber(vector<int>& nums) {int i = 0;int sum = 0;int ret = 0;while(i <= 31){//找到所有数第i位相加的结果for(auto e : nums){sum += (e>>i)&1;}if(sum % 3 == 1) ret |= 1<<i;sum = 0;i++;}return ret;}
};

题目分析:我们将nums中每个元素的某一位全部加到一起,总共有4中情况:3n个0+0、3n个0+1、3n个1+0、3n个1+1。无论哪种情况,都将加和结果%3,最后得到的0、1、0、1就是所求结果的每一个比特位。

扩展:我们可以把这一道题扩展到除了某个元素只出现一次,其他出现n次,只需在将每一位求和后%n即可。

class Solution {
public:vector<int> missingTwo(vector<int>& nums) {int n = nums.size() + 2;int tmp = 0;//1.将所有数字异或到tmp上for(auto e : nums) tmp ^= e;for(int i = 1 ; i <= n ; i++) tmp ^= i;//2.找到a、b中的比特位的那一位int j = 0;for(j = 0 ; j < 32 ; j++){if((tmp >> j) & 1) break;} //3.按照tmp位分成两组int a = 0, b = 0;for(auto e : nums){if((e >> j) & 1) a ^= e;else b ^= e;}//3.根据j位的不同,将所有的数划分为两类来异或for(int i = 1 ; i <= n ; i++){if((i >> j) & 1) a ^= i;else b ^= i;}return {a,b};}
};

题目分析:这道题依然是用位运算的方式解决,第一步,先将nums中所有的数异或到同一个变量tmp上,然后再把1~N也异或到这个变量上,最后得到的就是缺失的两个数字的异或。第二步,找到tmp中,比特位为1的那一位。第三步,根据x位的不同,将nums中的数字划分成两组,将这两组分别异或到两个变量上,就可以得到缺失的两个数字。


http://www.mrgr.cn/news/33479.html

相关文章:

  • MELON的难题- 华为OD统一考试(E卷)
  • Cpp类和对象(中)(4)
  • TryHackMe 第3天 | Pre Security (二)
  • 微信小程序教程:如何在个人中心实现头像贴纸功能
  • 英语(二)-写作常用词汇和句型范文
  • [Linux]用户管理指令
  • 2024/9/22 英语每日一段
  • [JavaEE] 网络编程----UDP / TCP 回显服务器
  • 华为OD机试 - N个选手比赛前三名、比赛(Python/JS/C/C++ 2024 E卷 100分)
  • 【原创】java+swing+mysql仓库管理系统设计与实现
  • 238 除自身以外数组的乘积
  • Oracle(139)如何创建和管理数据库用户?
  • 【Elasticsearch系列十九】评分机制详解
  • MySQL 的 ACID 属性:保障数据完整性的基石
  • 数据挖掘实战-基于SARIMA时间序列模型预测阿里巴巴股票数据趋势
  • 90%的人都不知道的国庆头像制作神器!AI智能一键搞定,快速上手!
  • BP神经网络
  • 240922-MacOS终端访问硬盘
  • DeepSeek 2.5本地部署的实战教程
  • ETCD学习使用