位运算基础

简介: 本文由blue编写,发布于2024年3月,主要讲解位运算的基础知识及其应用。内容涵盖计算二进制中1的个数、`x & -x`运算规则及其实用场景(如获取LowBit)、与、或、非、异或运算的定义与妙用,以及左移和右移操作。通过实例代码展示了如何利用位运算解决实际问题,例如信号灯灯管变化模拟。适合初学者学习位运算的核心概念与技巧。

位运算基础

作者:blue

时间:2024.3

1.计算二进制中1的个数

n=n&(n-1) //用就完了
#include <iostream>
using namespace std;
int count(int n)
{
   
    int sum=0;
    while(n)
    {
   
        n=n&(n-1);
        sum++;
    }
    return sum;
}
int main()
{
   
    int n;
    int sum=0;
    cin>>n;
    sum=count(n);
    printf("%d",sum);
    return 0;
}

应用:0二进制问题 - 蓝桥云课 (lanqiao.cn)

虽然有一半的测试数据会超时,但是强在代码容易写,而且不用思考,先拿一半分数再说

#include <iostream>
#define int long long
using namespace std;
int count(int n)
{
   
  int sum=0;
  while(n)
  {
   
    n=n&(n-1);
    sum++;
  }
  return sum;
}
signed main()
{
   
  int n,k;
  int ans=0;
  int sum;
  cin>>n>>k;
  for(int i=1;i<=n;i++)
  {
   
    sum=count(i);
    if(sum==k) ans++;
  }
  printf("%lld",ans);
  return 0;
}

2.位运算(x & -x)

~x:按位取反

-x 的值, 其实就是在x的值的基础上进行按位取反(~x)之后在增加1所得

x & -x == x & (~x + 1)

x 为偶数

偶数按位取反后一定是奇数,再+1,会影响进位。

0000 0100 1110, 取反后的结果就变成了 1111 1011 0001,而当这个值 + 1之后由于发生了进位, 即

1111 1011 0001 + 1 = 1111 1011 0010

这个结果再与最初的值相与后, 只会有一位保留为1

0000 0100 1110 & 1111 1011 0010 = 0000 0000 0010

如果一个偶数, 在执行 x & -x的操作的时候, 最后结果肯定有如下两个特征:

① 这个结果只有一位值是1, 其他位均是0
② 这个值的末位0的个数与原值保持一致

当一个偶数与它的负值相与时, 结果是能整除这个偶数的最大的2的幂, 即: m = n & -n , 则 n % m = 0, 且 m = 2 ^ k

x为奇数

奇数取反后的值一定是偶数, 而偶数的值 + 1之后, 并不会影响进位

所以进行x&-x后,剩下刚加上的那最后一位1

结论:“如果是x是奇数, 那x & -x 的结果一定是1

最终结论

当一个数与其取负后的值相与, 如果这个数是偶数, 则结果是能整除这个偶数的最大的2的幂(即: m = n & -n , 则 n % m = 0, 且 m = 2 ^ k), 如果这个数是奇数, 则结果必为1

用途: 一般可以用来获取某个二进制数的LowBit

lowbit ( n ) 定义为非负整数 n 在二进制表示下 “ 最低位的 1 及其后面的所有的 0 ” 的二进制构成的数值。

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

8.位运算(与,或,非,异或)

与运算运算符号为 & ,运算法则为遇0得0。也就是说只要有0,结果即为0

举例:1001 & 1100

    1 0 0 1
      &
    1 1 0 0
    ————
    1 0 0 0

妙用(x&1)可以用来判断二进制数x最后一位是不是1,是1就为1,不是1则为0;

可以用来快速判断奇偶数。

或运算运算符号为 | ,就是一个竖线,运算法则为遇1得1。也就是说,只要有1,结果就为1。

举例:1100 | 1010

    1 1 0 0
      |
    1 0 1 0
    ————
    1 1 1 0

非运算预算符号为 ~,就是一个波浪线,运算法则为按位取反,也就是遇1取0,遇0取1,即 ~1 = 0 , ~0 = 1;

举例: ~1001

    1 0 1 1
     ~
    ————
    0 1 0 0

异或运算运算符号为 ^,就是一个乘方符号,运算法则为相同取0,不同取1。异或运算,关键在异上面,异为1,否则为0

举例:1001 ^ 1001

    1 0 1 1
     ^
    1 0 0 1
    ————
    0 0 1 0

左移与右移

<<左移

很简单的来说就是把当前的二进制,整体往左边移动N个单位,N取决于你的表达式。

例如:32 << 1 = 64。
>>右移

很简单的来说,把当前的二进制,整体往右边移动N的单位,得到一个新的二进制。

例如:32 >> 1 = 16

image-20240310125759384.png

//用二进制数来表示信号灯的7个灯管,用异或运算来模拟灯管的变化
#include <stdio.h>
#include <string.h>
const int N = 1e5 + 1;
int check(int x)
{
   
    int num=0;
    while(x)
    {
   
        num += (x & 1);
        x = x >> 1;
    }
    return num;
}
int main()
{
       
               //abcdefg
    int pos[] = {
    0B1111110,
               0B0110000,
               0B1101101,
               0B1111001,
               0B0110011,
               0B1011011,
               0B1011111,
               0B1110000,
               0B1111111,
               0B1111011 };
    int i, len;
    int ans = 0;
    char s[N], t[N];
    scanf("%s", s);
    scanf("%s", t);
    len = strlen(s);
    for(i=0;i<len;i++)
    {
   
        ans += check(pos[s[i] - '0'] ^ pos[t[i] - '0']);
    }
    printf("%d", ans);
    return 0}
目录
相关文章
|
算法
关于按位运算与逻辑运算
本文介绍了按位运算与逻辑运算的基础知识,并通过一个实际问题展示了按位运算的应用。按位运算直接对二进制位操作,包括按位与(`&`)、或(`|`)、异或(`^`)、取反(`~`)、左移(`&lt;&lt;`)和右移(`&gt;&gt;`)。逻辑运算则针对布尔表达式,包含逻辑与(`&&`)、或(`||`)、非(`!`)。文中通过“寻找独特数字卡片”例题,利用异或运算特性解决数组中唯一单次出现的数字问题,算法时间复杂度为O(n),空间高效。
616 1
|
9月前
|
缓存 网络协议 安全
steam显示-118或-102该怎么解决?解决办法。
本文介绍了修复Steam常见问题的多种方法,包括使用第三方软件一键修复、检查网络连接、优化DNS设置、调整Hosts文件、关闭防火墙或安全软件以及使用网络加速器等实用技巧,帮助用户轻松解决Steam连接和运行问题。
679 0
|
弹性计算 Kubernetes 数据处理
KubeRay on ACK:更高效、更安全
阿里云 ACK 以托管组件化的方式给客户提供快速搭建Ray集群的能力,并通过结合使用阿里云的调度,存储,日志与监控,给用户提供更佳使用体验。
|
10月前
|
机器学习/深度学习 算法
位运算的总结--奇思妙解
目录前言先回顾常用的位运算1:给一个数 n ,确定它的二进制表示中的第x位是0 还是 12:将一个数 n 的二进制表示的第x 位修改成 1 3:将一个数 n 的二进制表示的第 x位修改成 0 4:与位图联系5:提取一个数(n)二进制表示中最右侧的 1(重要)6:干掉一个数(n)二进制表示中最右侧的 1(重要)7:要考虑位运算的优先级吗?(了解)8:异或(^)运算的运算律(重要)9:对于~的妙用实现++/--(知道有就行)在这篇文章中,我将总结我所知道的所有位运算的独特之处。这些妙用非常重要,运用得当可以显著
221 0
|
11月前
|
机器学习/深度学习 数据采集 JavaScript
用深度学习提升DOM解析——自动提取页面关键区块
本文介绍了一次二手车数据爬虫事故的解决过程,从传统XPath方案失效到结合深度学习语义提取的成功实践。面对懂车帝平台的前端异步渲染和复杂DOM结构,通过Playwright动态渲染、代理IP隐藏身份,以及BERT模型对HTML块级语义识别,实现了稳定高效的字段提取。此方法抗结构变化能力强,适用于复杂网页数据采集,如二手车、新闻等领域。架构演进从静态爬虫到动态爬虫再到语义解析,显著提升效率与稳定性。
374 13
用深度学习提升DOM解析——自动提取页面关键区块
|
10月前
|
定位技术 数据中心
安徽京准电钟分享:NTP授时服务器极速部署指南
安徽京准电钟分享:NTP授时服务器极速部署指南
467 14
|
12月前
|
JSON API 数据格式
一文读懂天猫商品详情 API 接口:功能、调用与实战攻略
天猫商品详情API为电商从业者、开发者和数据分析人员提供高效的商品数据获取途径。通过输入商品ID,可获取商品基本信息(名称、品牌等)、价格信息(售价、促销价等)、库存状态、商品描述及图片链接等详细内容。本文还提供了Python调用示例,包含签名生成、参数构建与请求发送等功能,帮助用户快速集成API,满足定价优化、市场分析等需求。使用时需替换示例中的AppKey与商品ID,并遵守平台规范。
600 16
|
C++
【天梯赛】L2-045 堆宝塔
最后 A 柱上剩下的宝塔作为一件成品,B 柱上剩下的彩虹圈被逐一取下,堆成另一座宝塔。堆宝塔游戏是让小朋友根据抓到的彩虹圈的直径大小,按照从大到小的顺序堆起宝塔。但彩虹圈不一定是按照直径的大小顺序抓到的。第二行按照宝宝抓取的顺序给出 N 个不超过 100 的正整数,对应每个彩虹圈的直径。//定义一个栈,T可以为int,float,double,char,string......在一行中输出宝宝堆出的宝塔个数,和最高的宝塔的层数。//检查栈是否为空,如果为空返回true,否则返回false。
374 8
|
存储 机器学习/深度学习 人工智能
探索未来科技:人工智能与区块链的融合之路
【10月更文挑战第14天】探索未来科技:人工智能与区块链的融合之路
755 1