位运算

位运算

计算机底层都是用二进制来表示的。每个数都可以表示成二进制的形式,位运算就是基于整数的二进制表示形式来进行的运算,所以运算起来还是很快的。

常用的运算符有6种,分别是 与&、或|、异或^、取反~、左移<<、右移>>

基础操作

运算符描述解释
&二进制对应位上都是1才是1
|二进制对应位上有1就是1
^异或二进制对应位上不同才是1
~取反0 变 1, 1 变 0
<<左移各二进位全部左移若干位,高位丢弃,低位补0
>>右移各二进位全部右移若干位,高位补什么取决于编译器

5 = ( 101 ) 2 6 = ( 110 ) 2 5 & 6 = ( 100 ) 2 5 ∣ 6 = ( 111 ) 2 5 ⊕ 6 = ( 011 ) 2 5 = (101)_2 \\ 6 = (110)_2 \\ 5 \& 6 = (100)_2 \\ 5 | 6 = (111)_2 \\ 5 \oplus 6= (011)_2 5=(101)26=(110)25&6=(100)256=(111)256=(011)2

⊕ \oplus 代表异或,计算机里面的符号是 ^.

一些公式

0 ^ n = n

n ^ n = 0

所以: n ^ m ^ m = n

乘 2 的非负整数次幂

n << m 代表的是 n ∗ ( 2 m ) n*(2^m) n(2m)

除以 2 的非负整数次幂

n >> m 代表的是 n / ( 2 m ) n / (2^m) n/(2m)

交换两个整数

n = n ^ m
m = n ^ m
n = n ^ m

注意顺序不能乱,可以仔细的想一想。

获取一个数二进制的某一位

(n >> m) & 1; // 获取 n 的第 m 位, 最低位的编号为 0

将一个数二进制的某一位设置为 0

n & ~(1 << m); // 将 n 的第 m 位设置为 0 ,最低位编号为 0

将一个数二进制的某一位设置为1

n | (1 << m); // 将 n 的第 m 位设置为 1 ,最低位编号为 0

将一个数二进制的某一位取反

n ^ (1 << m); // 将 n 的第 m 位取反 ,最低位编号为 0

移除二进制表示的最后一个1

n & (n - 1)

所以如果想知道一个数 n 的二进制有多少个 1, 可以这样算。

while(n){
	n = n & (n - 1);
	ans++;
}

每次都去掉二进制表示的最后一个 1,所以答案就是 ans。

获取二进制表示的最后一个1

(n & (n - 1)) ^ n

例题:

剑指 Offer 39. 数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入: [1, 2, 3, 2, 2, 2, 5, 4, 2]
输出: 2

有一个数的个数超过了数组长度的一半, 所以我们可以按照二进制的每一位来统计答案。

二进制只有 0 和 1, 对于每一位,统计一下0 和 1 出现的次数。如果 1 出现的次数大于一半,那么答案的这一位也是1,否则就是 0.

具体看代码就可以理解。

int majorityElement(vector<int>& nums) {
    int ans = 0;
    int n = nums.size();
    //统计每位数字的第i位二进制
    for(int i = 0; i < 32; i++){
        int cnt = 0;
        for(int j = 0; j < n; j++){
            //如果第i位为1, 那么 cnt++.
            if((nums[j] >> i & 1) == 1) cnt++;
        }
        //如果所有数字的二进制数中,第i位1比0多, 把答案的第 i 位变成 1.
        if(cnt > n / 2) ans ^= (1 << i);
    }
    return ans;
}

这个题还有一个不是位运算的解法, 而且非常优雅,感兴趣的同学可以去找一下题解,或者自己再想一想。

例题

剑指 Offer 15. 二进制中1的个数

请实现一个函数,输入一个整数(以二进制串形式),输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

示例 1:

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。

就是统计二进制有多少个 1, 我们上面也说了这个技巧,直接拿来用就可以了。

int hammingWeight(uint32_t n) {
    int cnt = 0;
    while(n){
        n = n & (n - 1);
        cnt++;
    }
    return cnt;
}

练习

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值