剑指offer面试题15——二进制中1的个数

题目描述

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

题目分析

1、可能引起死循环的解法:

基本思路:先判断整数二进制表示中最右边一位是不是1,接着把输入的整数右移一位,此时原来处于从右边数起第二位被移到最右边了,再判断是不是1,这样每移次动一位,知道整个整数变成0为止。

那么,如何判断一个整数的最右边是不是1呢? 如果一个整数与1做与运算的结果是1,则表示该整数最右边一位是1,否则是0。

//每次判断最高位,右移
int NumberOf1(int n){
    int count = 0;
    while(n){
        if(n & 1)
            count++;
        n = n >> 1;
    }
    return count;
}

注意:(1)把整数右移一位相当于把整数除以2,因为除法的效率比移位运算低得多,在编程中尽量使用移位代替乘除法。

(2)如果输入一个负数,如果最高位是1,右移时并不是简单地把最高位的1移到第二位,这是因为移位前是一个负数,仍然要保证移位后还是一个负数,所以移位后的最高位会设为1。如果一直右移,可能会陷入死循环,变成了0xFFFFFFFF。

2、常规解法:

首先把n和1做位与运算,判断n的最低位是不是1,接着把1左移一位得到2,再和n做与运算,判断n的次低位是不是1。这样反复左移。

//先判断n的最低位, 左移
class Solution {
public:
     int  NumberOf1(int n) {
         int count = 0;
         unsigned int flag = 1;
         while(n){
             if(n & flag)
                 count++;
             flag = flag << 1;
         }
         return count;
     }
};

循环次数等于整数二进制的位数(如32位)。

3、更好的解法:(整数中有几个1就只需要循环几次)

把一个整数减去1,都是把最右边的1变成0,如果他的右边还有0,则所有的0都变成1,而他左边的所有位都保持不变。把一个整数减去1再和原整数做与运算,相当于把它最右边的1变成0。

思路:把一个整数减去1,再和原整数做与运算,会把该整数最右边的1变成0.那么一个整数的二进制表示中有多少个1,就可以进行多少次这样的操作。

class Solution {
public:
     int  NumberOf1(int n) {
         int count = 0;
         while(n){
             ++count;
             n = (n-1) & n;
         }
         return count;
     }
};

 

你可能感兴趣的:(刷题)