当前位置:   article > 正文

算法(5)——位运算_c++ (n >> x) & 1

c++ (n >> x) & 1

一、位运算概述

  • 程序中的所有数在计算机内存中都是以二进制的形式存储的

  • 位运算(Bitwise operation)就是直接对整数在内存中的二进制位进行操作,因此其执行效率非常高

  • 在程序一般使用位运算进行操作,会大大提高程序的性能

位运算的本质

  • 位运算是在二进制之间操作,粗略地说就是 0 和 1 之间的转换

位运算时会将数值转换为32位整型来进行运算,所以位运算遇到小数时,直接处理掉小数部分当成整数来运算,并且要是一个数的二进制表示超过32位,或者运算完后超过32位,那么就会出问题。所以不是所有的情况都适用位运算(可以利用位运算进行取整操作)

二、位运算操作

位运算操作符有:

  • 按位非~

  • 按位与&

  • 按位或|

  • 按位异或^

  • 左移<<

  • 无符号右移>>>

  • 有符号右移>>

想必大家对这些操作符都很熟悉了,我在这里就不过多解释了

三、位运算相关操作

1、给一个数N,确定它的二进制表示中的第X位是0还是1?

(N>>X)&1

2、将一个数N的二进制第X位修改为1

N=N |(1<<X)

3、将一个数N的二进制第X位修改为0

N=N & (~(1<<X))

4、提取一个数(N)二进制表示中最右侧的1

N & -N

5、干掉一个数(N)二进制表示中最右侧的1

N & (N-1)

注意:我们在位运算时要关注位运算的优先级,我们最好都加括号(),这样就不会出错

四、位运算例题

4.1、判断字符串是否唯一

面试题 01.01. 判定字符是否唯一 - 力扣(LeetCode)

        题目描述:

        算法思路

利⽤「位图」的思想,每⼀个「⽐特位」代表⼀个「字符,⼀个 int 类型的变量的 32 位⾜够表⽰所有的⼩写字⺟。⽐特位⾥⾯如果是 0 ,表⽰这个字符没有出现过。⽐特位⾥⾯的值是 1 ,表⽰该字符出现过。

那么我们就可以⽤⼀个「整数」来充当「哈希表」。
        代码实现1
  1. class Solution {
  2. public:
  3. bool isUnique(string astr)
  4. {
  5. //位图
  6. int bitmap=0;
  7. for(auto e:astr)
  8. {
  9. int i=e-'a';
  10. if((bitmap>>i)&1)
  11. {
  12. return false;
  13. }
  14. bitmap=bitmap|(1<<i);
  15. }
  16. return true;
  17. }
  18. };

        代码实现2

  1. 哈希算法
  2. class Solution {
  3. public:
  4. bool isUnique(string astr)
  5. {
  6. if(astr.size()>26)
  7. {
  8. return false;
  9. }
  10. unordered_map<char,int> arr;
  11. for(int i=0;i<astr.size();i++)
  12. {
  13. arr[astr[i]]++;
  14. if(arr[astr[i]]>1)
  15. {
  16. return false;
  17. }
  18. }
  19. return true;
  20. }
  21. };

4.2、丢失的数字

268. 丢失的数字 - 力扣(LeetCode)

        题目描述

        算法思路

设数组的⼤⼩为 n ,那么缺失之前的数就是 [0, n] ,数组中是在 [0, n] 中缺失⼀个数形成 的序列。

如果我们把数组中的所有数,以及 [0, n] 中的所有数全部「异或」在⼀起,那么根据「异或」 运算的「消消乐」规律,最终的异或结果应该就是缺失的数~

        代码实现
  1. class Solution {
  2. public:
  3. int missingNumber(vector<int>& nums)
  4. {
  5. int xorsum=0;
  6. for(auto e:nums)
  7. {
  8. xorsum^=e;
  9. }
  10. for(int i=1;i<=nums.size();i++)
  11. {
  12. xorsum^=i;
  13. }
  14. return xorsum;
  15. }
  16. };

4.3、两整数之和

371. 两整数之和 - 力扣(LeetCode)

        算法思路

异或 ^ 运算本质是「⽆进位加法」;
按位与 & 操作能够得到「进位」;
然后⼀直循环进⾏,直到「进位」变成 0 为⽌。
        代码实现
  1. class Solution {
  2. public:
  3. int getSum(int a, int b)
  4. {
  5. while(b)
  6. {
  7. int x=a^b;
  8. unsigned int carry=(unsigned int)(a&b)<<1;
  9. a=x;
  10. b=carry;
  11. }
  12. return a;
  13. }
  14. };

4.4、只出现一次的数字Ⅱ

137. 只出现一次的数字 II - 力扣(LeetCode)

        题目描述

        算法思路

设要找的数位 ret 。由于整个数组中,需要找的元素只出现了「⼀次」,其余的数都出现的「三次」,因此我们可以根据所有数的「某⼀个⽐特位」的总和 %3 的结果,快速定位到 ret 的「⼀个⽐特位上」的值是0 还是 1

这样,我们通过 ret 的每⼀个⽐特位上的值,就可以将 ret 给还原出来。
        代码实现        
  1. class Solution {
  2. public:
  3. int singleNumber(vector<int>& nums)
  4. {
  5. map<int,int> freq;
  6. for(auto e:nums)
  7. {
  8. freq[e]++;
  9. }
  10. int k=0;
  11. for(auto [first,second]:freq)
  12. {
  13. if(second==1)
  14. {
  15. k=first;
  16. break;
  17. }
  18. }
  19. return k;
  20. }
  21. };

4.5、消失的两个数字

        题目描述

        算法思路:

本题就是 【丢失的数字】 + 【只出现一次的数字】 组合起来的题。

先将数组中的数和 [1, n + 2] 区间内的所有数「异或」在⼀起,问题就变成了:有两个数出现了「⼀次」,其余所有的数出现了「两次」。进⽽变成了  【只出现一次的数字】  这道题。

        代码实现

  1. class Solution {
  2. public:
  3. vector<int> missingTwo(vector<int>& nums)
  4. {
  5. int sum=0;
  6. for(auto e:nums)
  7. {
  8. sum^=e;
  9. }
  10. for(int i=1;i<=nums.size()+2;i++)
  11. {
  12. sum^=i;
  13. }
  14. //此时sum就是我们要找的两个数字的异或
  15. int bitdex=0;
  16. for(int i=0;i<32;i++)
  17. {
  18. if((sum>>i&1)==1)
  19. {
  20. bitdex=i;
  21. break;
  22. }
  23. }
  24. int a=0,b=0;
  25. for(int i=1;i<=nums.size()+2;i++)
  26. {
  27. if(((1<<bitdex)&i))
  28. {
  29. a^=i;
  30. }
  31. else
  32. {
  33. b^=i;
  34. }
  35. }
  36. for(auto e:nums)
  37. {
  38. if((1<<bitdex)&e)
  39. {
  40. a^=e;
  41. }
  42. else
  43. {
  44. b^=e;
  45. }
  46. }
  47. return {a,b};
  48. }
  49. };
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/780982
推荐阅读
相关标签
  

闽ICP备14008679号