zoukankan      html  css  js  c++  java
  • 一些位运算的技巧

    参考自:https://blog.csdn.net/deaidai/article/details/78167367

    奇技淫巧

    1.技巧一:用于消去x的最后一位的1

    x & (x-1)
    x = 1100
    x-1 = 1011
    x & (x-1) = 1000

    1.1.应用一 用O(1)时间检测整数n是否是2的幂次.

    思路解析:N如果是2的幂次,则N满足两个条件。
    1.N>0
    2.N的二进制表示中只有一个1
    一位N的二进制表示中只有一个1,所以使用N&(N-1)将唯一的一个1消去。
    如果N是2的幂次,那么N&(N-1)得到结果为0,即可判断。

    1.2.应用二 计算在一个 32 位的整数的二进制表示中有多少个 1.

    思路解析:
    由 x & (x-1) 消去x最后一位知。循环使用x & (x-1)消去最后一位1,计算总共消去了多少次即可。

    1.3.将整数A转换为B,需要改变多少个bit位

    思路解析

    这个应用是上面一个应用的拓展。

    思考将整数A转换为B,如果A和B在第i(0<=i<32)个位上相等,则不需要改变这个BIT位,如果在第i位上不相等,则需要改变这个BIT位。所以问题转化为了A和B有多少个BIT位不相同。

    联想到位运算有一个异或操作,相同为0,相异为1,所以问题转变成了计算A异或B之后这个数中1的个数。

    2.技巧二 使用二进制进行子集枚举

    应用.给定一个含不同整数的集合,返回其所有的子集

    思路就是使用一个正整数二进制表示的第i位是1还是0,代表集合的第i个数取或者不取。所以从0到2n-1总共2n个整数,正好对应集合的2^n个子集。

    3.技巧三.a^b^b=a

    3.1.应用一 数组中,只有一个数出现一次,剩下都出现两次,找出出现一次的。

    问题

    Given [1,2,2,1,3,4,3], return 4

    解题思路

    因为只有一个数恰好出现一个,剩下的都出现过两次,所以只要将所有的数异或起来,就可以得到唯一的那个数。

    3.2.应用二 数组中,只有一个数出现一次,剩下都出现三次,找出出现一次的。

    问题

    Given [1,1,2,3,3,3,2,2,4,1] return 4

    解题思路

    因为数是出现三次的,也就是说,对于每一个二进制位,如果只出现一次的数在该二进制位为1,那么这个二进制位在全部数字中出现次数无法被3整除。

    模3运算只有三种状态:00,01,10,因此我们可以使用两个位来表示当前位%3,对于每一位,我们让Two,One表示当前位的状态,B表示输入数字的对应位,Two+和One+表示输出状态。

     1 #include<stdio.h>
     2 
     3 void findNum(int *a,int n)
     4 {
     5     int ans=0;
     6     int bits[32]={0};
     7     for(int i=0;i<n;i++){
     8         for(int j=0;j<32;j++){
     9             bits[j]+=((a[i]>>j)&1);
    10         }
    11     }
    12     for(int i=0;i<32;i++){
    13         if(bits[i]%3==1) ans+=1<<i;
    14     }
    15     printf("%d
    ",ans);
    16 }
    17 int main()
    18 {
    19     int a[10]={1,1,2,3,3,3,2,2,4,1};
    20     findNum(a,10);
    21 }

    3.3.应用三 数组中,只有两个数出现一次,剩下都出现两次,找出出现一次的

    问题
    Given [1,2,2,3,4,4,5,3] return 1 and 5

    解题思路
    有了第一题的基本的思路,我们不妨假设出现一个的两个元素是x,y,那么最终所有的元素异或的结果就是res = x^y。并且res!=0,那么我们可以找出res二进制表示中的某一位是1,那么这一位1对于这两个数x,y只有一个数的该位置是1。对于原来的数组,我们可以根据这个位置是不是1就可以将数组分成两个部分。求出x,y其中一个,我们就能求出两个了。

     1 #include<stdio.h>
     2 
     3 void findNum(int *a,int n)
     4 {
     5     int ans=0;
     6     int pos=0;
     7     int x=0,y=0;
     8     for(int i=0;i<n;i++)
     9         ans^=a[i];
    10     int tmp=ans;
    11     while((tmp&1)==0){
    12     //终止条件是二进制tmp最低位是1
    13             pos++;
    14             tmp>>=1;
    15     }
    16     for(int i=0;i<n;i++){
    17         if((a[i]>>pos)&1){//取出第pos位的值
    18             x^=a[i];
    19         }
    20     }
    21     y=x^ans;
    22     if(x>y) swap(x,y);//从大到小输出x,y
    23     printf("%d %d
    ",x,y);
    24 }
    25 int main()
    26 {
    27     int a[8]={1,2,2,3,4,4,5,3};
    28     findNum(a,8);
    29 }

    找到最低位的1

    int lowbit(int x)
    {
        return x&(-x);
    }

    -

  • 相关阅读:
    SQL Server 造成cpu 使用率高的 6 原因
    SQL Server SQLOS
    flask数据库操作
    redis数据类型
    python3中__get__,__getattr__,__getattribute__的区别
    强弱类型,动静态语言
    函数式编程和面向对象编程
    数据库事务的四个特性和含义
    流畅的python
    Python中__repr__和__str__区别
  • 原文地址:https://www.cnblogs.com/jiamian/p/12194819.html
Copyright © 2011-2022 走看看