剑指Offer-15:二进制中1的个数(NumberOf1InBinary)

一、题目描述

在这里插入图片描述

二、解题思路

  • 解法1:逐步查看该数字的最低位,看是否为 1 1 ,然后把数字左移 1 1 位。时间复杂度为 O ( 32 n ) O(32n)
  • 解法2:将数字不断与 ( n 1 ) (n-1) 相与,每次计算完成后,只要数字不为 0 0 ,就说明存在 1 1 1 1

三、解题代码

解法1

class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count = 0;
        while(n){
            if(n & 1)
                count++;
            n = n >> 1;
        }
        return count;
    }
};

解法2

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

三、测试程序

/*******************************************************************
Copyright(c) 2016, Harry He
All rights reserved.

Distributed under the BSD license.
(See accompanying file LICENSE.txt at
https://github.com/zhedahht/CodingInterviewChinese2/blob/master/LICENSE.txt)
*******************************************************************/

//==================================================================
// 《剑指Offer——名企面试官精讲典型编程题》代码
// 作者:何海涛
//==================================================================

// 面试题15:二进制中1的个数
// 题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如
// 把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。

#include <cstdio>
/*
int NumberOf1_Solution1(int n)
{
    int count = 0;
    unsigned int flag = 1;
    while (flag)
    {
        if (n & flag)
            count++;

        flag = flag << 1;
    }

    return count;
}

int NumberOf1_Solution2(int n)
{
    int count = 0;

    while (n)
    {
        ++count;
        n = (n - 1) & n;
    }

    return count;
}
*/
int NumberOf1_Solution1(int n)
{
    int count = 0;
    while (n)
    {
        count++;
        n &= (n - 1);
    }
    return count;
}
int NumberOf1_Solution2(int n)
{
    int count = 0;
    while (n)
    {
        if (n & 1)
            count++;
        n = n >> 1;
    }

    return count;
}
// ====================测试代码====================
void Test(int number, unsigned int expected)
{
    int actual = NumberOf1_Solution1(number);
    if (actual == expected)
        printf("Solution1: Test for %p passed.\n", number);
    else
        printf("Solution1: Test for %p failed.\n", number);

    actual = NumberOf1_Solution2(number);
    if (actual == expected)
        printf("Solution2: Test for %p passed.\n", number);
    else
        printf("Solution2: Test for %p failed.\n", number);

    printf("\n");
}

int main(int argc, char *argv[])
{
    // 输入0,期待的输出是0
    Test(0, 0);

    // 输入1,期待的输出是1
    Test(1, 1);

    // 输入10,期待的输出是2
    Test(10, 2);

    // 输入0x7FFFFFFF,期待的输出是31
    Test(0x7FFFFFFF, 31);

    // 输入0xFFFFFFFF(负数),期待的输出是32
    Test(0xFFFFFFFF, 32);

    // 输入0x80000000(负数),期待的输出是1
    Test(0x80000000, 1);

    return 0;
}

四、运行结果

Solution1: Test for 0000000000000000 passed.
Solution2: Test for 0000000000000000 passed.

Solution1: Test for 0000000000000001 passed.
Solution2: Test for 0000000000000001 passed.

Solution1: Test for 000000000000000a passed.
Solution2: Test for 000000000000000a passed.

Solution1: Test for 000000007fffffff passed.
Solution2: Test for 000000007fffffff passed.

Solution1: Test for 00000000ffffffff passed.
Solution2: Test for 00000000ffffffff passed.

Solution1: Test for 0000000080000000 passed.
Solution2: Test for 0000000080000000 passed.

在这里插入图片描述

五、复盘

我发现LeetCode上的都是CodeInterview上的弱化版本,实际上CodeInterview里要考虑数据为负数的情况
那么我的第二种解法就不好使了,比如数据为0x80000000,这可是个负数
因为int型数据正数为原码,负数为补码。
最高位是符号位,正数最高位是0,负数最高位为1
那么对于负数1111 1111 1111 1111 1111 1111 1111 1111:其值为 1 -1‬
那么对于负数1000 0000 0000 0000 0000 0000 0000 0001:其值为 2 , 147 , 483 , 647 -2,147,483,647‬
但是别忘了 + 0 = = 0 +0 == -0 ,所以多出了一个数据,那么就使用 0 -0 1000 0000 0000 0000 0000 0000 0000 00000x8000000来表示更大的数字,即 2 , 147 , 483 , 648 -2,147,483,648
那么使用解法1来计算0x8000000,将会卡在 1 -1 然后进入死循环
为什么呢,因为负数在内存中以补码(补码:符号位不变,其余位按照原码取反加1)形式保存,右移时保证符号位不变,其余位向右移动到X位,在移动的过程中,高位补1
那么对于1000 0000 0000 0000 0000 0000 0000 0000,势必最后变成1111 1111 1111 1111 1111 1111 1111 1111,这个数字是-1,于是再怎么位移都是-1,死循环,所以跳出循环的条件还要加上是不是等于-1
综上,代码优化为:

int NumberOf1_Solution2(int n)
{
    int count = 0;
    if (n < 0)
    {
        if (n == -1)
            return 32;
        count++;
    }

    while (n && n != -1)
    {
        if (n & 1)
            count++;
        n = n >> 1;
    }
    return count;
}

猜你喜欢

转载自blog.csdn.net/weixin_44587168/article/details/105697425