位运算最基本的用法就是移位取值的使用。

1. 常见的位运算技巧

(1) 判断奇偶

奇数最后一位为1,偶数为0

if(num&1){} //奇数
else {} //偶数

(2) 交换两数

if(a!=b) a^=b,b^=a,a^=b;

(3) 变换符号

二进制取反+1就可以将正变负,负变正。

return ~a+1;

(4)取出某一位的数字

int val=(x >> i) & 1

2. 移位取值

这一类题目都运用到了前面提到的取出某一位数字的技巧,这种方法将位运算转化为类似字符串的操作形式,十分简便。

136 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素

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

解答:

假设数组是001,001,000,000,011,多余的元素是011,最后一位操作加起来取余2,余下了1,所以,多余元素就是1。

int singleNumber(vector<int>& nums) {
    int target = 0;
    for (int i = 0; i < 32; i++)
    {
        int sum = 0;
        for (auto x : nums)
            //取出单个比特的数字
            sum += (x >> i) & 1;
        int residue = sum % 2;
        target = target | residue << i;
    }
    return target;
}

137 只出现一次的数字 II

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。

输入: [0,1,0,1,0,1,99]
输出: 99

解答:

方法和上面一样,不过是取余3而已。

int singleNumber(vector<int>& nums) {
    int res=0;
    for(int i=0;i<32;i++)
    {
        int sum=0;
        for(auto x:nums)
            sum+=(x>>i)&1;
        int residue=sum%3;
        res|=residue<<i;
    }
    return res;
}

169 多数元素

给定一个大小为 n 的数组,找到其中的众数。众数是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。

输入: [2,2,1,1,1,2,2]
输出: 2

解答:

和上面两题一脉相承,如果数组有7个元素,而001是众数,则第0位的1的数量一定大于等于4,0的数量小于等于3,所以只需要比较0和1的数量就可以判断。

int majorityElement(vector<int>& nums) {
    int res=0;
    for(int i=0;i<32;i++)
    {
        int zeros=0;
        int ones=0;
        for(auto x:nums)
        {
            if((x>>i)&1) ones++;
            else zeros++;
        }
        if(ones>zeros) res|=1<<i;
    }
    return res;
}

190 颠倒二进制位

颠倒给定的 32 位无符号整数的二进制位。

输入: 00000010100101000001111010011100
输出: 00111001011110000010100101000000

解答:

利用栈的特性。

uint32_t reverseBits(uint32_t n) {
    stack<int> st;
    uint32_t res=0;
    for(int i=0;i<32;i++)
    {
        int val =(n>>i)&1;
        st.push(val);
    }
    for(int i=0;i<32;i++)
    {
        res|=st.top()<<i;
        st.pop();
    }
    return res;
}

191 位1的个数

编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量

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

解答:

极其简单,也可以一行解决return bitset<32>(n).count();

int hammingWeight(uint32_t n) {
    int res=0;
    for(int i=0;i<32;i++)
    {
        if((n>>i)&1)
            res++;
    }
    return res;
}