阳康后的第一篇博客,先来几道恶心二进制编程题

目录

一、统计二进制中1的个数

二、打印整数二进制的奇数位和偶数位

三、两个整数二进制位不同个数


一、统计二进制中1的个数

这是一道牛客网OJ题,感兴趣的话可以先做一遍再看解析哦 -> 牛客网的OJ链接

注意:上面的牛客网是接口型,不需要写主函数,系统默认主函数是存在的,只需要完成函数即可。

题目描述:输入一个整数 n ,输出该数32位二进制表示中1的个数。其中负数用补码表示。

思路:假设想打印一个整数的十进制的每一位,例如123,我们会先让123%10,得到3,再让123/10,得到12。然后再把12%10,以此类推就能得到它们的每一位,所以总结一下,一个整数的十进制只需循环除10和模10。然而得到二进制的每一位也是如此,只要将二进制循环模2和除2即可。例如:11的二进制为0000 1011,首先让11%2=1,这个1就是二进制序列上最后一个1,再让11/2=5,5的二进制就是101(就是上面加粗部分)。既然有思路,那我们就来看看怎么写代码吧。

按照上面的思路,不难可以写出这样的代码,但是提交发现代码错误。

举个栗子:当n = -1时,不为0进入循环,-1%2不等于1,cnt不会++,走到n /= 2,带入n的值发现n的结果为0,0为假cnt自然而然就输出0了。说明以上代码对负数是不太友好的。下面有2个办法可以解决改问题。

解决办法1:首先可以把-1当做无符号数来看待,所以只需要在int n前加上 unsigned

解决方法2:可以运用&这个操作符( 点我,快速了解操作符

假设有一个二进制序列为(有32位,简写):00001111,我们&上一个1就能得到最低位的1(加粗),那么问题来了,如何得到其他位上的1呢?这时位移操作符就派上用场了,只需要把00001111右移1位,然后再&上一个1即可。

最后,对于这题,我再为大家展现一个绝妙的解题方法!!

有个表达式是: n = n & (n- 1)

这是一个非常神奇的表达式,当n = 11,它的二进制为1011,n - 1 = 10,它的二进制是1010,1011 & 1010 = 1010(十进制:10),有没有发现,最低位的1不见了;接着,n - 1 = 9,它的二进制为1001,然后再让1010 & 1001 = 1000,这时,最低位的1又不见了。所以,每执行这个表达式,n的二进制最低位上的1都会消失,这个表达式执行几次,就会有多少个1。


对于上面的表达式,还能这么用

假设用编程实现n是否为2的k次方。

思路:只要是2的k次方数字,它们的2进制的表示中只有一个1

例如:2的3次方 ---- 1000
2的2次方 ---- 100
2 的 4次方 ---- 10000
这时就能灵活运用刚刚讲过的表达式:if(n & (n - 1) == 0)

二、打印整数二进制的奇数位和偶数位

题目内容:获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列。

思路:

假设要打印上图中的二进制序列的奇数位和偶数位,那么如何得到它们对应的二进制数字呢?通过上一题也不难发现,只要将(n >> i) & 1即可

代码实现:

#include <stdio.h>
void Print(int n)
{
    printf("奇数位:");
    int i = 0;
    for (i = 31; i >= 1; i -= 2)
    {
        printf("%d ", (n >> i) & 1);
    }
    printf("\n");

    printf("偶数位:");
    for (int i = 32; i >= 2; i -= 2)
    {
        printf("%d ", (n >> i) & 1);
    }
    printf("\n");
}
int main()
{
    int n = 0;
    scanf("%d", &n);
    Print(n);  //封装一个Print函数
    return 0;
}

三、两个整数二进制位不同个数

描述:输入两个整数,求两个整数二进制格式有多少个位不同(点我,做题!

思路:先将n和m进行按位异或(^),此时n和m相同的二进制位清零,不同的二进制位为1,最后统计异或后结果的二进制位有几个1即可 。( 点我查看操作符详解
#include <stdio.h>
int one(int m,int n)
{
    int cnt = 0;
    int tmp = m ^ n;
    while(tmp)
    {
        tmp = tmp & (tmp - 1);
        cnt++;
    }
    return cnt;
}
int main()
{
    int m = 0;
    int n = 0;
    scanf("%d %d",&m,&n);
    
    int res = one(m,n);
    printf("%d\n",res);
    return 0;
}

四、总结

阳康后第一篇博客,欢迎大佬们指点,后面开始继续输出。加油!!!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值