位运算练习

题目列表源于:acwing
题目源于leetcode

题目:762. 二进制表示中质数个计算置位

题意:

给你两个整数 left 和 right ,在闭区间 [left, right] 范围内,统计并返回 计算置位位数为质数 的整数个数。
计算置位位数 就是二进制表示中 1 的个数。
例如, 21 的二进制表示 10101 有 3 个计算置位

思路:

数字中包含二进制中1的个数,采取lowbit方式进行实现,其运算一个数据的实践复杂度为O(m), m为数字中包含1的个数,然后通过数字标记素数的形式判断是否是素数,这么做会多占用一些空间,因为数据量比较小,大概20个左右的数据,因此可以采取二进制的形式对其进行标记,mask=665772=10100010100010101100。

代码:
class Solution {
public:
    
    int lowbit(int x){return x&(-x);}
    int bit_num(int x){
        int bt = 0;
        while(x){
            bt++;
            x -= lowbit(x);
        }
        return bt;
    }
    int countPrimeSetBits(int left, int right) {
        
        int cn = 0;
        for(int i = left; i <= right; i++){
            // cout<<bit_num(i)<<endl;
            if((1<<bit_num(i))&665772)cn++;
        }
        return cn;
    }
};
// 1 10 11
// 100 101 110 
// 111 1000 1001
// 1010

题目:136. 只出现一次的数字

题意

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

思路:

由于异或有个性质 a ^ a = 0,所有出现两次的数据,直接相互抵消,所以只需要遍历一次即可将所有出现两次的数据剔除,只剩下出现一次的数据。

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

题目:137. 只出现一次的数字 II

题意:

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

思路:

类似于二进制的形式,这里采取三进制的形式,将数据拆成二进制的形式,相应位置为3个的时候则表明数据出现过三次。

代码:
class Solution {
public:
    
    int singleNumber(vector<int>& nums) {
        int ans = 0;
        for(int i = 0; i < 32; i++){
            int tot = 0;
            for(auto num: nums){
                tot += (num>>i)&1;
            }
            if(tot % 3)ans |= (1<<i);
        }
        return ans;
    }
};

题目:260. 只出现一次的数字 III

题目:

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

思路:

因为只包含一个可以遍历一遍求出,所以将其进行分组,分成两组,遍历一遍将其求出,如何分组呢,先异或遍历一遍所有的数据,当某位数为1,则表明这位数,仅剩的两个数在这位不同,因此根据这里的数据是1还是0进行区分。

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

        long a = 0, b = 0;
        for(int i = 0; i < nums.size(); i++){
            if(nums[i]& kind){
                a ^= nums[i];
            }
            else b ^= nums[i];
        }
        vector<int>res;
        res.push_back(a);
        res.push_back(b);
        return res;
    }
};

题目:201. 数字范围按位与

题意:

给你两个整数 left 和 right ,表示区间 [left, right] ,返回此区间内所有数字 按位与 的结果(包含 left 、right 端点)。

思路:

最直观的想法是获取left,最低为的1位置,然后对其进行加1,观察其与之right之间的关系,超过right则保留,不超过right则置为0,进行累计。

代码:
class Solution {
public:
    long lowbit(long x){return x&(-x);}
    int rangeBitwiseAnd(int left, int right) {
        int ans = 0;
        long n = left, m = right;
        while(n){
            int bit = lowbit(n);
            if(n+bit > m)ans += bit;
            n -= bit;
        }
        return ans;
    }
};

题目:477. 汉明距离总和

题意:

两个整数的 汉明距离 指的是这两个数字的二进制数对应位不同的数量。
给你一个整数数组 nums,请你计算并返回 nums 中任意两个数之间 汉明距离的总和 。

思路:

统计二进制相应位置1的个数c,然后乘以(n-c),进行累加。

代码:
class Solution {
public:
    int totalHammingDistance(vector<int>& nums) {
        int sum = 0;
        for(int i = 0;  i < 31; i++){
            int cn = 0 ;
            for(auto num: nums){
                if(num&(1<<i))cn++;
            }
            sum += (nums.size()-cn)*cn;
        }
        return sum;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值