输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

本文介绍了一种高效计算整数二进制表示中1的个数的方法,并提供了三种不同的实现方式,包括一种可能陷入无限循环的错误示例及其修正方案。

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

链接:https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8
来源:牛客网


public class Solution {
    //从n的2进制形式的最右边开始判断是不是1
    /*
    * 该解法如果输入时负数会陷入死循环,
    * 因为负数右移时,在最高位补得是1
    * 二本题最终目的是求1的个数,那么会有无数个
    * 1了。
    */
    //-------------可能陷入死循环的解法---------------------
    public static int NumberOf1_CanNotUse(int n) {
        int count = 0;
        while (n != 0) {
            /*
            * 用1和n进行位与运算,
            * 结果要是为1则n的2进制形式
            * 最右边那位肯定是1,否则为0
            */
            if ((n & 1) == 1) {
                count++;
            }
            //把n的2进制形式往右推一位
            n = n >> 1;
        }
        return count;
    }
    //---------------正解--------------------------------
    //思想:用1(1自身左移运算,其实后来就不是1了)和n的每位进行位与,来判断1的个数
    private static int NumberOf1_low(int n) {
        int count = 0;
        int flag = 1;
        while (flag != 0) {
            if ((n & flag) != 0) {
                count++;
            }
            flag = flag << 1;
        }
        return count;
    }
    //--------------------最优解 时间复杂度为有几个1就执行几次----------------------------
    public static int NumberOf1(int n) {
        int count = 0;
        while (n != 0) {
            ++count;
            n = (n - 1) & n;
        }
        return count;
    }
    public static void main(String[] args) {
        //使用n=10,二进制形式为1010,则1的个数为2;
        int n = -10;
        System.out.println(n + "的二进制中1的个数:" + NumberOf1(n));
    }

<think>好的,用户想要用C语言实现计算负数在内存中二进制表示1个数,并且要求使用位操作符。我需要仔细思考这个问题,确保解决方案正确且高效。 首先,回顾一下之前用户提供的引用内容。引用[4]中提到,整数在内存中以补码形式存储,负数补码是其原码取反加一。因此,计算负数二进制1个数时,必须考虑其补码形式。例如,-1补码是全部位为1,所以1个数应该等于系统位,比如32位系统就是32个1。 用户之前尝试过不同的方法,比如通过取模和除法逐位检查(引用[2]),但这种方法对于负数可能无法正确工作,因为负数二进制表示补码中会有多个1。例如,使用这种方法计算-1的话,由于负数的符号位问题,循环可能提前终止或者得到错误结果。 接下来,引用[4]还提到了n & (n-1)的算法,这个算法可以高效地消除二进制中的最右边的1,直到变为0。对于正来说,这个方法是有效的,但负数补码形式下,直接使用这个循环可能会导致无限循环,因为负数右移时在C语言中是算术右移,高位补1,所以负数的情况下,传统的逐位检查可能需要处理符号位的问题。 因此,正确的做法是将变量视为无符号整数来处理,这样可以避免符号位的影响。例如,将int类型的负数转换为unsigned int,这样右移时会补0而不是1,从而正确统计所有位的1,包括符号位。 结合引用[3]中的方法,设计一个,将传入的int值转换为unsigned int,然后使用n & (n-1)的方法来统计1个数。这样可以确保负数被正确处理,因为转换为无符号后,其二进制表示与原补码相同,但移位操作会补0,从而正确遍历所有位。 还需要测试一下这个方法是否正确。比如,对于-1,转换为unsigned int后,所有位都是1,循环会执行32次(假设是32位系统),每次消除一个1,最终count为32,正确。对于其他负数,比如-3,补码11111111 11111111 11111111 11111101,转换为无符号后,同样会有30个1,所以count应该是30。 总结步骤: 1. 将传入的int值转换为unsigned int类型,避免符号扩展问题。 2. 使用n = num & (num - 1)循环来消除最右边的1,直到num为0。 3. 每次循环增加计器。 这样处理可以确保无论是正还是负数,都能正确统计其二进制补码中的1个数。</think>要计算负数在内存中二进制补码表示1个数,需通过位操作符结合补码特性实现,具体步骤如下: ### 实现思路 1. **补码特性**:负数在内存中以补码形式存储,例如-1补码是`11111111 11111111 11111111 11111111`(32位系统)[^4] 2. **无符号转换**:将`int`强制转换为`unsigned int`,避免符号位扩展影响位运算 3. **高效位运算**:使用`n & (n - 1)`算法消除最右侧的1,直到值为0 ### 代码实现 ```c #include <stdio.h> int count_binary_ones(int num) { unsigned int u_num = (unsigned int)num; // 转换为无符号处理补码 int count = 0; while (u_num) { count++; u_num &= (u_num - 1); // 消除最右侧的1 } return count; } int main() { int num = -1; printf("%d的二进制补码含%d个1\n", num, count_binary_ones(num)); return 0; } ``` ### 代码解析 1. **强制类型转换**:`(unsigned int)num`将负数转换为无符号,保留其补码二进制表示 2. **循环消除1**:`u_num &= (u_num - 1)`每次操作消除二进制中最右侧的1 - 例如`1110 & 1101 = 1100`消除第二个1 3. **时间复杂度**:O(k),k为二进制1个数,比遍历32位更高效 输出示例: ``` -1二进制补码含32个1 ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值