15 二进制中1的个数

题目描述:

 输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。例:表示成二进制是1001,有两位是1,因此函数返回2。

测试用例:

 1)正数(包括边界值:1、0x7FFFFFFF(除了首位为0,其他都为1,最大的正数)

 2)负数(包括边界值 0x80000000(只有首位是1,其他位为0,”最小的负数“)、0xFFFFFFFF(所有位全是1,指-1)

 3)0

解题思路:

 1)常规解法:

n与二进制1相与,可以判断n的最低位是不是为1。接着把1左移1位变成2,再和n相与,能知道n的次低位是不是为1。。。

//int 32 bit
class Solution {
public:
     int  NumberOf1(int n) {
         int count = 0;
         unsigned int flag = 1; 
         while(flag){
             if(n&flag)
                 count++;
             flag = flag<<1;
         }
         return count;
     }
};

循环的次数等于正数二进制的位数(int 32bit) 

2)欣赏的解法  

 规律:把一个整数减去1(就是把最右边的1变成0,如1100-1=1011),再和原整数做运算,会把该整数的最右边的1变成0(1100&1011=1000)。那么一个整数的二进制表示中有多少个1,就可以进行多少个这样的操作。

class Solution {
public:
     int  NumberOf1(int n) {
         int count = 0;
         while(n){ //n!=0时(正数/负数),二进制中一定含有1.
             count++;
             n = n&(n-1);  //每运行一次,二进制中减少一个1
         }
         return count;
     }
};

3)使用右移运算,错误代码:当n是负数时,会陷入无限循环

class Solution {
public:
     int  NumberOf1(int n) {
         int count = 0;
         while(n){ 
             if(n&1)
                 count++;
             n = n>>1;
             //当n为负数时,右移,高位用1补位,最后终所有位都是1(0xFFFFFFFF)陷入死循环
         }
         return count;
     }
};  

修改,对负数另做运算:负数首位一定是1,count计数加1。将其变为0,右移补位为0,同正数一样。

class Solution {
public:
     int  NumberOf1(int n) {
         int count = 0;
         if(n < 0){ //n为负数,把首位的1变0,count加1。剩下的按正数处理
             n = n & 0x7FFFFFFF;
             ++count; //n不为0,一定含有1
         }
         while(n != 0){
             count += n & 1;
             n = n >> 1;
         }
         return count;
     }
};

4)使用内建函数

class Solution {
public:
     int  NumberOf1(int n) {
        return bitset<32>(n).count();
     }
};//

-- bitset存储二进制数位,bitset中的一个元素一般只占1 bit。  

-- bitset中的每个元素都能单独被访问,例如对于一个叫做foo的bitset,表达式foo[3]访问了它的第4个元素,就像数组一样。

-- 整数类型和布尔数组都能转化成bitset。

-- bitset的大小在编译时就需要确定。如果你想要不确定长度的bitset,请使用 vector<bool>。  

-- bitset的运算就像一个普通的整数一样,可以进行与(&)、或(|)、异或(^)、左移(<<)、右移(>>)等操作。

https://www.cnblogs.com/RabbitHu/p/bitset.html 

https://www.cnblogs.com/magisk/p/8809922.html  

基础知识:

[1] 位运算有5种操作:与&、或|、异或^、左移<<、右移>>。

左移 m<<n :最左边的n位将被抛弃,同时在最右边补上n个0。

右移 m>>n:

-- 如果数字是无符号数值,用0填补左边的n位

-- 如果数字是有符号数值,则用数字的符号位填补最左边的n位

           正数:右移,左侧补n个0

           负数:右移,左侧补n个1

[2] 右移1位相当于除以2运算,因为除法的效率比移位运算要低的多,在实际的编程中应该尽可能的用移位代替除法

[3] 因为右移对正负的补位不同,在编写程序时尽量使用左移。 

原文地址:https://www.cnblogs.com/GuoXinxin/p/10400581.html