基础位运算

位运算

一、几个基础的位运算

1、‘<<’(左移)


就是将一个数对应的二进制整体向左移且高位溢出则丢弃,末尾补零。

> <img src="C:\Users\KaIOR\AppData\Roaming\Typora\typora-user-images\image-20231127222601526.png" alt="image-20231127222601526" style="zoom:50%;"
/>2、‘>>’(右移)

2、‘>>’(右移)

与上面的左移相反,一个数的二进制整体向右移丢弃最低位,不同的是如果原先的二进制的第一位是1,则补1,0则补0.

>

3、‘&’(与)、‘|’(或)、‘^’(异或)

1.与运算就是只要有0就是0,全为1才是1。

2.或运算就是有1就有1全0才为0.

3.异或运算是两者相同就为0,两者不同就为1(类似于消消乐)。
在这里插入图片描述

二、简单的几道位运算的题

1.获取某个数的二进制数的某一位是0还是1

void Test1()
{
	int number;//判断的数字
	int n;//判断的位数(二进制的第一位为0位)

	cin >> number >> n;

	int ret = (number >> n) & 1;

	cout << ret << endl;
}

在这里插入图片描述

2.将二进制的第x位的改成1

void Test2()
{
	int number;//修改的数字
	int n;//修改的位数(二进制的第一位为0位)

	cin >> number >> n;
	//0001 0111 0001 1101 0011 //94675
	//0001 1111 0001 1101 0011 //127443
	int ret = (1 << n) | number;

	cout << ret << endl;
}

在这里插入图片描述

3.将二进制的第x位的改成0

void Test3()
{
	int number;//修改的数字
	int n;//修改的位数(二进制的第一位为0位)

	cin >> number >> n;
	//0001 0111 0001 1101 0011 //94675
	//0001 1111 0001 1101 0011 //127443
	
	//1.
	//int ret = (1 << n) ^ number;

	//2.
	int ret = (~(1 << n)) & number;

	cout << ret << endl;

	cout << ret << endl;
}
```![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/04ce2d3ddc084656ae7f485ea700305a.png)

4.提取一个数最右侧的1

把一个int类型的数,提取出最右侧的1来,例如:

对应的二进制位 0000 0110,那么取出来的应该是0000 0010
void Test4()
{
	int number;//修改的数字
	cin >> number;
	//0001 0111 0001 1101 0011 //94675
	// 
	//1110 1000 1110 0010 1101 //-94675
	//0001 0111 0001 1101 0010

	int ret = (number) & (-number);
	cout << ret << endl;

}


在这里插入图片描述

5.删除最右侧的1

void Test5()
{
	int number;//修改的数字
	cin >> number;
	//0001 0111 0001 1101 0011 //94675
	// 
	//1110 1000 1110 0010 1101 //-94675
	//0001 0111 0001 1101 0010

	int ret = (number) & (number-1);
	cout << ret << endl;

}

在这里插入图片描述

6.260. 只出现一次的数字 III

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

题目的意思很简单就是将数组中两个只出现一次的数字找出来并返回。

在这里插入图片描述

一拿到题我们的想法可能是用哈希表,但是题目中要求我们使用常量的额外空间去进行解决。

所以我们就想之前那道只出现一次数字的题是用异或解决的,所以我们就可以去想这道题是否也可以用异或的思想解决呢?

答案是:能!


相比于那题来说这题的数字是两个,所以我们就就想到是不是应该分成两组,两组同时异或,两组异或的结果就是两个答案,那要怎么分组呢?

通过观察两个数来说,从低位向高位看起的时候,总会出现一个不同的二进制位,像5和3则是第一位不同(二进制的最左边为第0位),所以这就是3和5的一个不同之处,所以我们可以将数组中分为两类,一类是第一位为0的数字,另一类是第一位为1的数字。

那么我们要怎么得到……0000010这样的数组呢?

很简单就是现将数组中所有数字异或,最后得到的就是3和5异或的结果这样就可以得到从左边开始的第一个不同的位的数据(……000110),然后就变成了提取最后一位的1的问题,只需将该数据与该数据的负数&操作就可以得到(……010)。

在分组:即可得到结果。

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int sum=0;
        for(auto num:nums)
        sum^=num;
        if(sum==INT_MIN)//防止溢出
        sum=INT_MIN;
        else
        sum=(sum)&(-sum);//目的是通过与运算将最后一位1区别出来,因为只有一位数
        //该位为1
        int first=0;int end=0;
        for(auto num:nums)
        {
            if(num&sum)
            first^=num;
            else
            end^=num;
        }
        return {first,end};
    }
};
            first^=num;
            else
            end^=num;
        }
        return {first,end};
    }
};

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值