位运算的简单使用

位运算的介绍

运算符名称及其规则例子
~取反(~1 = 0, ~0 = 1)~11101 = 10
&按位与(1&1 = 1, 0&1 = 1&0 = 0&0 = 0)11001 & 10100 = 10000
|按位或(1|1 = 0|1 = 1|0 = 1, 0|0 = 0)1001 | 10 = 1011
^按位异或(0^1 = 1^0 = 1, 0^0 = 1^1 = 0)101001 ^ 11000 = 1001
<<左移1000 << 1 = 10000
>>右移1000 >> 1 = 100

位运算的一些使用

异或,与,或都满足交换律和结合律:

a^b = b^a, a^b^b= a^(b^b), a&b = b&a, a&b&b = a&(b&b),a|b = b|a, a|b|b = a|(b|b)

判断一个数a是否为偶数,一般为 a % 2 == 0。还可以用为运算实现:a&1 == 0

判断一个数是否为2的次幂    x&(x - 1) == 0  (等于0是)

a<<i = a * pow(2, i)     a>>i = a/pow(2, i)      (i + j) / 2 还可以表示为 (i + j) >> 1

0^a = a, a^a = 0,  a^b^b = a

异或可以完成不进位的加运算:11001 ^ 10000 =  01001

例题一:只出现一次的数字(力扣 136    简单)

题目链接:136. 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/single-number/

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

示例 1:

输出:[ 2, 2, 1]

输出:

示例 2:

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

输出:

题目分析:

异或的运算满足交换律和结合律, 而且 a^0 = a, a ^ a = 0, a ^ b ^ a = b ^ b ^ a = a, 在数组中只有一个数只出现一次, 其余的都出现了两次,将数组中的全部数都异或一次即可找出只出现一次的数。

代码:
 

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int ans = 0;
        for(int i = 0; i < nums.size(); i ++)
            ans ^= nums[i];
        return ans;
    }
};

 例题 2:只出现一次的数字II(力扣 137    中等)

题目链接:137. 只出现一次的数字 II - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/single-number-ii/

题目:给你一个数组nums,除某个元素仅出现一次外,其余每个元素都恰出现三次。请你找出并返回那个只出现一次的元素。

示例 1:

输入:nums = [ 2, 2, 3, 2]

输出:3 

示例 2:

输入:nums = [ 0, 1, 0, 1, 0, 1, 99]

输出:99 

题目分析:除了一个数只出现一次其余每个数都出现了三次,可以将每个数转化为32二进制, 对 每个二进制对应的数进行求和,并且对3取模。因为其他出现了三次,如果一个位的和对3取模对于1, 那么只出现的一次的数可以找到在这个位置存在。例如[ 3, 3, 3, 4] , 这些数变为32位二进制数就是[0000000000000000000000000000011, 0000000000000000000000000000011, 0000000000000000000000000000011, 0000000000000000000000000000100],将这些数的每一位的数进行求和得到0000000000000000000000000000133,对每位数对3取模得到0000000000000000000000000000100,等于4。

代码:

class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int n = nums.size(), ans = 0;
        for(int i = 0; i < 32; i ++)
        {
            int sum = 0;
            for(int j = 0; j < n; j ++)
                sum += (nums[j] >> i) & 1;
            if(sum % 3 == 1)
                ans |= (1 << i);
        }
        return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值