常见位运算及其经典算法题(1)

常见位运算及其经典算法题(1)

位运算顾名思义,是对整数的二进制位直接进行操作的运算。由此很多算法便有了更优解,大大提高了效率。如果你之前没有接触过位运算或者淡忘了,这篇文章或许会对你很有帮助。

1.六大核心运算符

<<(左移运算符)

规则:左移n位,低位补0

例如:5的二进制为0101,5<<2即0101左移两位,变成010100,即20

所以5<<2==20
我们可以发现:根据二进制转十进制的计算,原数字二进制中整体往左移动n位,就是乘以2^n,所以左移运算符的重要用途就是快速计算乘2的幂。

>>(右移运算符)

规则:右移n位,高位补符号位

例如:5>>1,即0101右移两位,等于0010;

(-5)>>1:

5的二进制位0000 0101(原码),求负数的二进制规则就是它对应的正数取反 ,+1,即

取反:1111 1010;+1:1111 1011。即-5=1111 1011(8位)

所以右移一位即:1111 1101,把它转回十进制,即-1,取反

0000 0011等于3,而根据上文表粗的原则,1111 1101=-3,即-5>>1==-3

&(按位与运算符)

规则:两个整数的每一位二进制比较,两个中有0结果就是0,其他都是1

例如:5(0101)& 3(0011)== 1(0001)

同理>>可以计算x//2^n(向下取整)

||(按位或运算符)

规则:两个整数的每一位二进制比较,两个中有1结果就是1,其他都是0

例如:5(0101)|| 3(0011)== 7(0111)

^(按位异或运算符)

规则:相同位0,相反为1,无进位相加

例如:5(0101)^ 3(0011)== 6(0110)

~(按位取反运算符)

规则:0变1,1变0

2.位运算常用结论

  • 取出二进制第i位:(x >> i)& 1
  • 将第i位改成1:n = n | ( 1 << i )
  • 将第i位改成0:n = n & ( ~ ( 1 << i ) )
  • 提取二进制中最右侧的1:n & ( -n )
  • 将二进制中最右侧的1变成0:n & (n-1)
  • 异或运算律:a ^ 0 = a. a ^ a = 0. a ^ b ^ c=a ^ (b ^c)

3.经典例题

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

这道题我们可以用set数据结构快速解决。但还有一种方法,便是位运算。

题中所给字母均为小写,所以一个符合条件的字符串最多包含a-z 26个英文字母。而整型有32位。我们可以从前往后遍历字符串,得出每个字符关于a的偏移量,将对应位的0变成1.代表此字母已经出现,如果后续再出现就返回false

cpp 复制代码
class Solution {
public:
   bool isUnique(string astr) {
       int flag=0;//每一位的0/1便是判断正误的关键
       for(auto e:astr)
       {
           int offset=e-'a';
           if(flag&(1<<offset))//判断此位是否已经为1
           {
               return false;
           }
           flag=flag|(1<<offset);//将此字母存入flag中
       }
       return true;
   }
};

2. leetcode371. 两整数之和

我们看到这道题后,就能大概率猜出是要用到位运算的知识点.

而这里便用到了异或^无进位相加的性质.

例如2^3==1(0001),异或以后惊奇的发现结果就是无进位相加后的结果,所以我们现在只需算出进位,再将两者异或,知道进位为0便可算出结果.

进位的表达式是(a&b)<<1.例如:

算到这里后,再将0001与0100异或得到0101,他俩的进位为0000,即0101就是结果5

cpp 复制代码
class Solution {
public:
    int getSum(int a, int b) {
        while(b!=0)
        {
            int x=a^b;//^的无进位相加
            unsigned int carry=(unsigned int)(a&b)<<1;//记录进位
            a=x;
            b=carry;
        }
        return a;
    }
};

今天就是这些东西。如有疑问,欢迎打在评论区。

主页还有更多优质内容OvO

相关推荐
love_muming8 分钟前
二叉树操作全解析:从递归到层序遍历
java·数据结构·算法·二叉树
Darkwanderor14 分钟前
多线程的互斥问题和互斥锁解决互斥问题
linux·c语言·c++
键盘会跳舞15 分钟前
C++:std::pair 源码级深度剖析 —— 关联容器的基石
开发语言·c++·pair·关联容器
(Charon)19 分钟前
【C++】手写线程安全队列:mutex + condition_variable 实现生产者消费者模型
c语言·开发语言·c++
.道阻且长.9 小时前
2.LeetCode算法习题讲解--双指针--复写零
算法·leetcode·职场和发展
·薯条大王9 小时前
经济实惠玩云服务器|一台云服务器多人共用,子账号配置教程
java·linux·运维·服务器·汇编·c++·python
To_OC11 小时前
LC 438 找到所有字母异位词:暴力超时后,我靠滑动窗口一招搞定
javascript·算法·leetcode
Forever Nore13 小时前
学完C语言力扣第一题做不来正常吗
数据结构·算法
hansang_IR14 小时前
【题解】LC:倍增 / 区间并查集(Range Parallel Unionfind)
c++·算法·并查集