Sword refers to offer (C++)-JZ15: the number of 1 in binary (algorithm-bit operation)

Author: Zhai Tianbao Steven
Copyright statement: The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source

Title description:

Input an integer n, and output the number of 1s in the 32-bit binary representation of the number. Negative numbers are expressed in two's complement.

Data range: −2^31<=n<=2^31−1

That is, the range is: −2147483648<=n<=2147483647

Example:

enter:

10

return value:

2

illustrate:

The 32-bit binary representation of 10 in decimal is 0000 0000 0000 0000 0000 0000 0000 1010, with two 1s in it.

Problem-solving ideas:

This question examines bit operations. Three ways of solving problems.

1) Cyclic bitwise comparison

       For a violent cycle, it is enough to count the 1 of each bit.

2) Bit operation formula n&(n-1)

       The bit operation formula n&(n-1) can change the rightmost 1 of the number to 0. For example, 1011 is 1010 after subtracting one, and 1010 is obtained by AND operation; another example is 1010, which is 1001 after subtracting one, and 1000 is obtained by AND operation.

       Use this property to loop, when n is 0, just exit the loop and stop counting.

3) Divide and conquer

       Take the 32-bit number A as an example, 1111 1111 1111 1111 1111 1111 1111 1111. Using the idea of ​​​​divide and conquer to solve problems, the following will show you the process of divide and conquer step by step.

3.1) divided into 16 groups

       The 32 bits are a group of two digits, set 16 groups of 01, and then 16 groups of 10.

       0x55555555 = 0101 0101 0101 0101 0101 0101 0101 0101

       0xaaaaaaaa = 1010 1010 1010 1010  1010 1010 1010 1010

       And operation with the number A can get the number of 1 in each group, for example, 11 and 01 get 01, 11 and 10 get 10, and then 10 is shifted right by 1 to become 01, 01+01 gets 10 which is 2, which is 11 The number of 1.

       After the above calculation, the number A becomes A1: 1010 1010 1010 1010 1010 1010 1010 1010.

3.2) divided into 8 groups

       The 32-bit is a group of four, set 8 groups of 0011, and then 8 groups of 1100.

       0x33333333 = 0011 0011 0011 0011 0011 0011 0011 0011

       0xcccccccc = 1100 1100 1100 1100 1100 1100 1100 1100

       And operation with the number A1 can get the number of 1 in each group, for example, 1010 and 0011 get 0010, 1010 and 1100 get 1000, then 1000 is shifted right by 2 to become 0010, 0010+0010 gets 0100 which is 4, which is 1111 The number of 1. Smart students have discovered the pattern here, which can be considered as two sets of two-digit numbers combined into one set of four-digit numbers.

       After the above calculation, the number A1 becomes A2: 0100 0100 0100 0100 0100 0100 0100 0100.

3.3) divided into 4 groups

       The 32-bit is a group of eight bits, set 4 groups of 0000 1111, and then 4 groups of 1111 0000.

       0x0f0f0f0f = 0000 1111 0000 1111 0000 1111 0000 1111

       0xf0f0f0f0 = 1111 0000 1111 0000 1111 0000 1111 0000

       And operation with the number A2 can get the number of 1 in each group, such as 0100 0100 and 0000 1111 to get 0000 0100, 0100 0100 and 1111 0000 to get 0100 0000, then 0100 0000 right shift 4 becomes 0000 0100, 0000 0100+0000 0100 gets 0000 1000 which is 8, which is the number of 1 in 1111 1111. The final result of each group of numbers is actually the number of 1s in the group of numbers.

       After the above calculation, the number A2 becomes A3: 0000 1000 0000 1000 0000 1000 0000 1000.

3.4) divided into 2 groups

       The 32 bits are set as a group of sixteen bits, set 2 groups of 0000 0000 1111 1111, and then 2 groups of 1111 1111 0000 0000.

       0x00ff00ff = 0000 0000 1111 1111  0000 0000 1111 1111

       0xff00ff00 = 1111 1111 0000 0000  1111 1111 0000 0000

       And operation with the number A3 can get the number of 1 in each group, such as 0000 1000 0000 1000 and 0000 0000 1111 1111 to get 0000 0000 0000 1000,0000 1000 0000 1000 and 1111 1111 0000 0000 to get 000 0 1000 0000 0000, then 0000 1000 0000 0000 shifted right by 8 becomes 0000 0000 0000 1000, 0000 0000 0000 1000+0000 0000 0000 1000 to get 0000 0000 0001 0000 which is 16, which is the number of 1 in 1111 1111 1111 1111 .

       After the above calculation, the number A3 becomes A4: 0000 0000 0001 0000 0000 0000 0001 0000.

3.5) Divide into 1 group

       32 bits as a set.

       0x0000ffff = 0000 0000 0000 0000  1111 1111 1111 1111

       0xffff0000 = 1111 1111 1111 1111  0000 0000 0000 0000

       The AND operation with the number A4 can get the number of 1s in each group, that is, 0000 0000 0001 0000 plus 0000 0000 0001 0000 is equal to 0000 0000 0010 0000, which is 32.

       The reason why this number A is used is because this number can be intuitively obtained to the logic of this method.

       After the above calculation, the number A4 becomes A5: 0000 0000 0000 0000 0000 0000 0010 0000. That is the end result.

Test code:

1) Cyclic bitwise comparison

class Solution {
public:
    // 1的个数
    int  NumberOf1(int n) {
        int count = 0;
        //遍历32位
        for(int i = 0; i < 32; ++i){
            //按位比较
            if((n & (1 << i)) != 0)   
                count++;
        }
        return count;
     }
};

2) Bit operation formula n&(n-1)

class Solution {
public:
    // 1的个数
    int NumberOf1(int n) {
        int count = 0;
        // 当n为0时停止比较
        while(n){  
            n &= n - 1;
            count++;
        }
        return count;
     }
};

3) Divide and conquer

class Solution {
public:
    // 1的个数
    int NumberOf1(int n) {
        int temp = n;
 
        // 0x55555555 = 0101 0101 0101 0101  0101 0101 0101 0101
        // 0xaaaaaaaa = 1010 1010 1010 1010  1010 1010 1010 1010
        temp = (temp & 0x55555555) + ((temp & 0xaaaaaaaa) >> 1);
 
        // 0x33333333 = 0011 0011 0011 0011  0011 0011 0011 0011
        // 0xcccccccc = 1100 1100 1100 1100  1100 1100 1100 1100
        temp = (temp & 0x33333333) + ((temp & 0xcccccccc) >> 2);
 
        // 0x0f0f0f0f = 0000 1111 0000 1111  0000 1111 0000 1111
        // 0xf0f0f0f0 = 1111 0000 1111 0000  1111 0000 1111 0000
        temp = (temp & 0x0f0f0f0f) + ((temp & 0xf0f0f0f0) >> 4);
 
        // 0x00ff00ff = 0000 0000 1111 1111  0000 0000 1111 1111
        // 0xff00ff00 = 1111 1111 0000 0000  1111 1111 0000 0000
        temp = (temp & 0x00ff00ff) + ((temp & 0xff00ff00) >> 8);
 
        // 0x0000ffff = 0000 0000 0000 0000  1111 1111 1111 1111
        // 0xffff0000 = 1111 1111 1111 1111  0000 0000 0000 0000
        temp = (temp & 0x0000ffff) + ((temp & 0xffff0000) >> 16);
        return temp;
     }
};

Guess you like

Origin blog.csdn.net/zhaitianbao/article/details/131892751