位运算

位移运算

  • <<运算

    • a<<b 表示把a转为二进制后左移b位(在后面添加 b个0)。例如100的二进制表示为1100100,100左移2位后(后面加2个零):1100100<<2 =110010000 =400,可以看出,a<<b的值实际上就是a乘以2的b次方,因为在二进制数后面添加一个0就相当该数乘以2,2个零即2的2次方 等于4。通常认为a<<1比a*2更快,因为前者是更底层一些的操作。因此程序中乘以2的操作尽量用左移一位来代替。

    • 定义一些常量可能会用到<<运算。你可以方便的用1<<16 -1 来表示65535(unsingned int 最大值16位系统)。很多算法和数据结构要求数据模块必须是2的幂,此时就可以用<<来定义MAX_N等常量。

  • >>运算

    • 和<<相似,a>>b表示二进制右移b位(去掉末b位),相当于a除以2的b次方(取整)。我们经常用>>1来代替 /2(div 2),比如二分查找、堆的插入操作等等。想办法用>>代替除法运算可以使程序的效率大大提高。最大公约数的二进制算法用除以2操作来代替慢的出奇的%(mod)运算,效率可以提高60%。
  • n & 1 就是取最左边位

  • n >>= 1(n = n>>1)就是将n右移一位

数学运算转化为位运算:

  • 向下整除 n//2 (C++中就是n/2)等价于右移一位 n >> 1;

  • 取余数n%2 等价于判断二进制最右位 n & 1;

JS15 二进制中 1 的个数(位移运算)

class Solution {
public:
    int hammingWeight(uint32_t n) {
        unsigned int res =0; // c++ 使用无符号数
        while(n!=0){
            res += n & 1;
            n >>= 1;  // 将二进制数字 n 无符号右移一位
        }
        return res; 
        
    }
};

JS16 数值的整数次方:实现pow(x,n)(位移运算)

class Solution {
public:
    double myPow(double x, int n) {
        if(x == 0.0f) return 0.0;
        long b = n;  // 将n存入long变量,int32 变量区间n∈[−2147483648,2147483647] ,因此当n=−2147483648 时执行n=−n 会因越界而赋值出错。解决方法是先将 n 存入 long 变量 b,后面用 b 操作即可
        double result = 1.0;
        // 当 幂次为负时
        if(b < 0){
            x = 1/x;
            b = -b;
        }
        // 
        while(b > 0){
            if((b&1) == 1) result*=x;
            x *= x;
            b >>= 1;
        }
        return result;
    }
};

JS56 数组中数字出现的次数I(异或运算)

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int x=0, y=0; // 记录只出现一次的两个数字
        int n =0;  // 记录异或结果
        int m =1;  // 为了获取x和y异或结果中第一个1出现的位置,即从右到左 x和y第一个不同的位置
        // 1.遍历nums进行异或,实际最后结果是x和y的异或结果
        for(int num:nums){
            n ^=num;
        }
        // 2.循环左移计算m即x和y异或结果中第一个1出现的位置
        while((n & m) == 0){
            m <<= 1;
        }
        // 4、通过m拆分nums为两个子数组,并进行异或
        for(int num:nums){
            if(num & m) x^= num;  // 当num&m!=0
            else y^=num; // 当num&m==0
        }
        // 5. 返回出现一次的数字
        return vector<int> {x,y};
    }
};

数组中数字出现的次数II(异或运算)

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ones=0, twos =0;
        for(int num:nums){
            ones = ones ^ num & ~twos;
            twos = twos ^ num & ~ones;
        }
        return ones;
    }
};

JS65 不用加减乘除做加法

class Solution {
public:
    int add(int a, int b) {
        while(b !=0){
            int c = (unsigned int)(a & b) << 1;
            a ^= b;
            b = c;
        }
        return a;
    }
};
posted @ 2021-07-18 16:53  夏目的猫咪老师  阅读(167)  评论(0编辑  收藏  举报