码迷,mamicode.com
首页 > 其他好文 > 详细

[剑指offer 15] 二进制中1的个数

时间:2020-11-13 13:03:07      阅读:3      评论:0      收藏:0      [点我收藏+]

标签:min   特点   优化   mingw   移位   测试   精简   strong   比特   

请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9?表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。

测试用例1:

技术图片

测试用例2:
技术图片

测试用例3:
技术图片

首先来分析题目,要统计二进制中1的个数,那么我们首先想到的是 要将此数的每个比特位都要遍历一遍,然后判断为1count++,最后返回count。就写出如下代码

int hammingWeight(uint32_t n) {
        int count = 0;
        while(n)
        {
            if(n&1)
                count++;

            //此处移位时,如果n为负数可能会导致死循环
            n >>= 1;
        }
        return count;
    }

上面的代码在统计无符号数时,结果是正确的,但是,在算负数时,可能会导致死循环。
此处我们采用的 位运算 来代替 除法运算,因为计算机中除法的效率要比比移位运算要低得多。我们在实际编程中要尽量地用移位运算符代替乘除法。
再者我们来讨论一下测试用例为负数。右移运算符的特点是,右移n位的时候,最右边的n位将被丢弃。在右移处理最左边位的情形比较复杂。如果数字是一个无符号值,则用0填补最左边的n位;如果数字为有符号数,则用数字的符号位填补最左边的n位。也就是说,如果数字原先是正数,则右移之后在最左边补n个0;如果数字原先是负数,则右移之后在最左边补n个1。 所以负数在进行移位时,最终由于最高位一直补1导致最终结果陷入死循环。故设计出上述代码是由问题的,我们可以对其进行调整。

  • 正确示范1:
int hammingWeight(uint32_t n) {
        int count = 0;
        unsigned int flag = 1;
        while(flag)
        {
            if(n&flag)
                count++;

            flag = flag << 1;
        }
        return count;
    }

为了避免死循环,此处我们不右移输入的数字n,而是把n和1 按位与 ,判断i的最低位是不是为1,接着把i左移1位,再和n做按位与运算。这样反复右移就能计算出n中二进制位1的个数。这种解法惟一的不足之处是无论n中二进制位有多少个1,都要进行32次循环。那么还能不能在优化一下呢,答案是肯定可以,来看一下最终比较完美的解答:
完美解答:

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

此处将位运算的灵活性体现到了机制,可以看出代码设计的非常巧妙精简。其精髓就在于此句 n = (n-1)&n 。大家可以自己体会一下此处的妙笔。

[剑指offer 15] 二进制中1的个数

标签:min   特点   优化   mingw   移位   测试   精简   strong   比特   

原文地址:https://blog.51cto.com/14289099/2546327

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!