C语言的三种方法解决牛客网上热题|求二进制在内存中含1的个数

求一个二进制在内存里面存放了多少个1,也就是相当于求这个二进制数的补码中有多少个1。

这里给大家展示三种不同的方法。

第一种写法(易错) 这里给大家展示的是不完全正确的写法

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int count_one(int n)
{
    int count = 0;
    while (n)//当n为0的时候自动跳出
    {
        if (n % 2 == 1)//当n的补码模2等于1的时候,也就是说n的补码的最后一位必定是1,count累加
        {
            count++;
        }
        n = n / 2;//不管末位数是否为1,进一次循环,就利用二进制的特性除以2将最右边的数扔掉,最左边补符号位,无符号位补0
    }
    return count;
   }

int main()
{
    //求一个整型数存在内存里面存放了多少个1(求补码中有多少个1)
    int n = 0;
    int count = 0;
    scanf("%d", &n);
    count = count_one(n);

    printf("count = %d\n", count);

    return 0;
}

如果你写代码的时候以为你的代码这样就可以完成任务的时候,那你就错了,上面的写法仅当n是正数的时候是正确的

当n为负数时

当n = -1的时候,结果为0,而众所周知 -1的补码有32个1

探究一下原因:

当n进入count_one函数的时候, -1模2, -1是不够除2的,会商0,所以count不会++, - 1 / 2也只会商0,当n = 0跳出循环return count,所以当n = -1的时候就会得0(如图)

当一个数是负数的时候,上面的代码就是存在问题的,该如何解决问题呢?

答:既然负数会让这段代码出现错误的结果,那我们就让接收的数恒为正数即可,即让接收n的时候无视符号位,我们让原本接收的int n改变成unsigned int n,就可以解决问题了

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int count_one(unsigned int n)//将int类型换成unsigned int,将有符号位换成无符号位这时代码就正确了
{
    int count = 0;
    while (n)
    {
        if (n % 2 == 1)
        {
            count++;
        }
        n = n / 2;
    }
    return count;
}

int main()
{
    //求一个整型数存在内存里面存放了多少个1(求补码中有多少个1)
    int n = 0;
    int count = 0;
    scanf("%d", &n);
    count = count_one(n);

    printf("count = %d\n", count);

    return 0;
}

第二种方法

我们知道-1的补码 10000000000000000000000000000001

而1的补码是 00000000000000000000000000000001

此时-1&1会得到 00000000000000000000000000000001

从这里可以简单看出:当1按位与上某一个数的时候会得到1本身

我们可以利用这一特点,让一个数和1进行按位与,当这个数的最末尾那个数按位与1 == 1的时候,也就是说这个数的末尾数也是1,再向右移一位,继续按位与1,重复该动作,这样也可以计算出1的个数了

代码实现:

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int count_one(int n)
{
    int i = 0;
    int count = 0;
    for (i = 0; i < 32; i++)//-1的补码是10000000000000000000000000000001
    {                        //1的补码是 00000000000000000000000000000001  两者相与等于1的时候,表示-1的末位数位1
        if (((n >> i) & 1) == 1)//当按位与1后,再向右位移i位,就达到了-1中的数逐个与1的效果
        {
            count++;
        }
    }
    return count;
}

int main()
{
    //求一个整型数存在内存里面存放了多少个1(求补码中有多少个1)
    int n = 0;
    int count = 0;
    scanf("%d", &n);
    count = count_one(n);

    printf("count = %d\n", count);

    return 0;
}

但该方法存在一定的缺点:就是不管是什么数,都要与1进行31次比较,最后才能判断1的个数

第三种方法

这是一种比较经典的处理方法,大家可以好好参考一下

假设n=13,则它的补码为 1101

则n-1的补码为 1100

此时令n=n&(n-1),会得到 1100

此时n再减1得 1011

此时再令n=n&(n-1)得 1000

n-1 0111

n=n&(n-1)得 0000

此时我们可以发现一个规律:每当n-1后再按位与一个n,会使这个数最右边得那个1消失,当该操作重复下去的时候,n最终会变成0。

我们可以通过这个规律可以用来求出n的补码中有几个1。

代码实现

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>

int count_one(int n)
{
    int count = 0;
    while (n)
    {
        n = n&(n - 1);
        count++;
    }
    return count;
}

int main()
{
    //求一个整型数存在内存里面存放了多少个1(求补码中有多少个1)
    int n = 0;
    int count = 0;
    scanf("%d", &n);
    count = count_one(n);

    printf("count = %d\n", count);

    return 0;
}

在这三种方法里面,方法三当然是最高效、最实用的,但也是最让人难以想到的。

今天就给大家分享这三种方法解决牛客网上的热题。

如有错误遗漏,欢迎指正,一起学习,一起进步。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值