位运算(&、^、补码、lowbit操作)

首先介绍一些基本概念

按位与操作&

是一种位运算,它逐位比较两个二进制数,并根据如下规则返回一个新的二进制数:

  • 1 & 1 = 1
  • 1 & 0 = 0
  • 0 & 1 = 0
  • 0 & 0 = 0

简单来说,只有当两个对应位都是 1 时,结果才是 1;否则结果为 0

按位与操作的示例

假设有两个整数 5 和 3,它们的二进制表示分别是:

  • 5 的二进制:0101
  • 3 的二进制:0011

异或操作(XOR,^

是一种位运算符,它对两个二进制数的每一位进行比较,并根据如下规则生成一个新的二进制数:

  • 相同的位:结果为 0
  • 不同的位:结果为 1

示例:

假设有两个数 53,它们的二进制表示分别是:

  • 5 的二进制表示:0101
  • 3 的二进制表示:0011
  • 现在对它们进行异或运算:
  •   0101  (5)
    ^ 0011  (3)
    -------
      0110  (结果是 6)
    

    补码

比如5的二进制串是:"101",那么~5(补码)就是"010"。全部取反即可

lowbit操作

是一种在二进制数中获取数字的 最低位的1 的值的操作,常用于一些算法和数据结构中,比如树状数组(Fenwick Tree)等。

Lowbit定义:对于一个整数 xlowbit(x) 返回它的二进制表示中最右边的 1 及其对应的值(即最低位的 1 的值)。lowbit(x) 的计算方式是:lowbit(x) = x & -x

这个公式利用了二进制的补码性质来找到 x 中的最低位 1

为什么 x & -x 可以得到 lowbit?

  • 对于一个数 x,它的 负数-x)可以通过取补码表示。负数 -x 的补码是 x 的反码(即逐位取反)加 1
  • x & -x 的结果正好是 x 中最低位的 1,其他所有位都是 0。原因是 -x 在二进制上会保留 x 中从最低位的 1 及其后面的所有 0,其他高位则取反。

示例:

12 为例:

  • 12 的二进制表示为:1100
  • -12 的二进制表示为:0100(将 1100 取反并加 1
  •   1100  (12)
    & 0100  (-12)
    -------
      0100  (结果是 4)
    

 

 二进制中1的个数(模板题)

给定一个长度为 n 的数列,请你求出数列中每个数的二进制表示中 1 的个数。

输入格式

第一行包含整数 n。

第二行包含 n 个整数,表示整个数列。

输出格式

共一行,包含 n 个整数,其中的第 ii 个数表示数列中的第 ii 个数的二进制表示中 11 的个数。

数据范围

1≤n≤100000,
0≤数列中元素的值≤10^9

输入样例:

5
1 2 3 4 5

输出样例:

1 1 2 1 2

代码 

#include <iostream>

using namespace std;

int n;

int lowbit(int x){
    return -x & x;
}

int main()
{
    int n;
    cin >> n;
    
    while(n --){
        int x;
        int res = 0;
        cin >> x;
        
        while(x){
            res ++;
            x -= lowbit(x);
        }
        
        cout << res << " ";
    }
    
    return 0;
}

构造最小位运算数组|| (lowbit操作的应用)

传送门. - 力扣(LeetCode)

给你一个长度为 n 的

质数

数组 nums 。你的任务是返回一个长度为 n 的数组 ans ,对于每个下标 i ,以下 条件 均成立:

  • ans[i] OR (ans[i] + 1) == nums[i]

除此以外,你需要 最小化 结果数组里每一个 ans[i] 。

如果没法找到符合 条件 的 ans[i] ,那么 ans[i] = -1 。

质数 指的是一个大于 1 的自然数,且它只有 1 和自己两个因数。

示例 1:

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

输出:[-1,1,4,3]

解释:

  • 对于 i = 0 ,不存在 ans[0] 满足 ans[0] OR (ans[0] + 1) = 2 ,所以 ans[0] = -1 。
  • 对于 i = 1 ,满足 ans[1] OR (ans[1] + 1) = 3 的最小 ans[1] 为 1 ,因为 1 OR (1 + 1) = 3 。
  • 对于 i = 2 ,满足 ans[2] OR (ans[2] + 1) = 5 的最小 ans[2] 为 4 ,因为 4 OR (4 + 1) = 5 。
  • 对于 i = 3 ,满足 ans[3] OR (ans[3] + 1) = 7 的最小 ans[3] 为 3 ,因为 3 OR (3 + 1) = 7 。

示例 2:

输入:nums = [11,13,31]

输出:[9,12,15]

解释:

  • 对于 i = 0 ,满足 ans[0] OR (ans[0] + 1) = 11 的最小 ans[0] 为 9 ,因为 9 OR (9 + 1) = 11 。
  • 对于 i = 1 ,满足 ans[1] OR (ans[1] + 1) = 13 的最小 ans[1] 为 12 ,因为 12 OR (12 + 1) = 13 。
  • 对于 i = 2 ,满足 ans[2] OR (ans[2] + 1) = 31 的最小 ans[2] 为 15 ,因为 15 OR (15 + 1) = 31 。

提示:

  • 1 <= nums.length <= 100
  • 2 <= nums[i] <= 109
  • nums[i] 是一个质数。

代码

class Solution {
public:
    int lowbit(int x){
        return -x & x;
    }
    vector<int> minBitwiseArray(vector<int>& nums) {
        int n = nums.size();
        for(int i = 0;i < n;i ++){
            int x = nums[i];
            if(x == 2){
                nums[i] = -1;
                continue;
            }
            nums[i] ^= lowbit(~x) >> 1;
        }
        return nums;
    }
};

加油

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值