位运算专题(个人理解)

Acwing 位运算专题

位运算介绍:

什么是位运算呢?位运算就是二进制数据进行运算的运算符,这里我们主要说到左移,右移,按位与,按位或,按位取反,异或。

1.左移<<
1010<<1
1010左移一位后:10100
即向左移动,低位补0

2.右移>>
1010右移一位后:0101
各二进位全部右移若干位,对无符号数,高位补0,有符号数,右移补1

3.按位与&
按位与与代码中的逻辑运算从差不多,两个都是1才是1,否则是0
如:1 0 1 0
  & 1 1 0 0
  ————————————
    1 0 0 0

4.按位或|
按位或和我们代码中加的逻辑运算差不多,在对两个二进制数进行或运算时,只要其中一个有1,那么就是1,两个都为0才是0
如:1 0 1 0
 |  0 1 1 0
 _____________
    1 1 1 0

5.按位取反~
1变0,0变1
如:~1010
取反后:0101

6.异或
相同为零,不同为1
如:  1 0 1 0 0 1
  ^   1 1 0 0 1 0
    _______________
      0 1 1 0 1 1

小技巧:


去掉最后一位
x>>1
 
在最后一位加个0
x<<1
 
在最后一位加个1
(x<<1)|1
 
把最后一位变成1
x|1
 
把最后一位变成0
(x|1)-1
 
最后一位取反
x^1
 
把右数第k为变成1
x|(1<<(k-1))
解释:将1向左移动k-1位,第k位是1,1到k-1位是0
 
吧右数第k位变成0
x&(~(1<<(k-1)))
解释:1向左移动k-1位,第k位是1,1到k-1位是0,取反后在与

​

​

位运算符优先级比较靠后,结合使用时一般需加上括号

例1 .不用加减乘除做加法

写一个函数,求两个整数之和,要求在函数体内不得使用 +、-、×、÷+、-、×、÷ 四则运算符号。

数据范围

−1000≤num1,num2≤1000−1000≤num1,num2≤1000

样例
输入:num1 = 1 , num2 = 2

输出:3
// 1100
// 1010
//10110
class Solution {
public:
    int add(int num1, int num2)
    {
        int a,b;
        a=num1^num2;//将不进位的相加
        b=(num1&num2)<<1;//将进位的相加
        return a+b;
    }
};

例二 将 x 的二进制表示中第 i 位和第 j 位的值互换,并输出互换后的结果

给定一个正整数 xx,请你将 xx 的二进制表示中第 ii 位和第 jj 位的值互换,并输出互换后的结果。

注意: xx 的二进制表示的最右边为第 00 位。

输入格式

共一行,包含三个整数 x,i,j

输出格式

一个整数,表示互换后的结果。

数据范围

1≤x≤2^31−11≤x≤2^31−1,
0≤i,j≤30.

输入样例1:
38 2 4
输出样例1:
50
输入样例2:
1 0 2
输出样例2:
4

分四种情况:

1. 两个位置均为1

2.两个位置均为0

3.一个位置为1,一个位置为0

4.一个位置为0,一个位置为1

1和2两种情况不需要做处理

AC代码:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int m,a,b,result;
	cin>>m>>a>>b;
	result=m;
	int i=m>>a&1;
	int j=m>>b&1;
	if(i&&!j)
	result=m-(1<<a)+(1<<b);//减去原有位置上1的值加上变化后1位置的值
	if(!i&&j)
	result=m+(1<<a)-(1<<b);//加上原有位置上1的值减去变化后1位置的值
	cout<<result<<endl;
	return 0; 
}

例三 数组中只出现一次的两个数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。

请写程序找出这两个只出现一次的数字。

你可以假设这两个数字一定存在。

数据范围

数组长度 [1,1000][1,1000]。

样例
输入:[1,2,3,3,4,4]

输出:[1,2]

AC代码:

​
class Solution {
public:
    vector<int> findNumsAppearOnce(vector<int>& nums) 
    {
        int m=1,n,j=0,x=0,y=0;
        n=nums.size();
        for(int i=0;i<n;i++)//先遍历异或得出x异或y的值
        {
            j^=nums[i];
        }
        while((j&m)==0)//找出第一个x和y不相等的二进制位
        {
            m<<=1;
        }
        for(int i=0;i<n;i++)
        {
            if(nums[i]&m)//将含x和含y的分为两组
            x^=nums[i];
            else
            y^=nums[i];
        }//最终异或出来的两数即为x和y的值
        return vector<int>{x,y};
    }
};

​

下一篇 力扣 2401. 最长优雅子数组

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值