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

发布于:2023-01-11 ⋅ 阅读:(176) ⋅ 点赞:(0)

题目描述:编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为 汉明重量))。

示例 1:输入:n = 11 (控制台输入 00000000000000000000000000001011)    输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
示例 2:输入:n = 128 (控制台输入 00000000000000000000000010000000)   输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
示例 3:输入:n = 4294967293 (控制台输入 11111111111111111111111111111101,部分语言中 n = -3)   输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。

设计一个变量count 来记录 ‘1’的个数
接下来用一个循环 , 不停的用n处以2,获得的余数存入栈中,余数是‘1’则 count 加1。

class Solution {
public:
    int hammingWeight(uint32_t n) 
    {
        stack<int> st;
        //将十进制无符号整数转化为二进制类型,并依次存入栈中
        while(n>0)
        {
            st.push(n%2); 
            n = n/2;
        }

        //将二进制数从栈中依次取出,并计算‘1’的个数
        int count=0;
        while(!st.empty())
        {
            if(st.top() == 1) count++;
            st.pop();   
        } 
        return count;  
    }
};
class Solution {
public:
    int hammingWeight(uint32_t n) 
    {
        //十进制转化为二进制,对2取余数(0、1),二进制‘1’的个数即是余数为1的个数累加
        if(n == 0) return 0;
        int count = 0;
        while(n > 0)
        {
            count += n%2;
            n = n/2;
        }
        return count;
    }
};
class Solution {
public:
    int hammingWeight(uint32_t n) {
        int count = 0;
        while(n>0)
        {
            if(n%2 == 1) count++;
            n /= 2;
        }
        return count;
    }
};

 

  1. ">>"右移     操作规则:正数前面补零,负数前面补1

    "<<"左移    操作规则:无论正负数,后面补零。 

逐位判断
       根据 与运算 定义,设二进制数字 n ,则有:
               若 n & 1 = 0,则 n 二进制 最右一位 为 0 ;
               若 n & 1 = 1 ,则 n 二进制 最右一位 为 1 。
       根据以上特点,考虑以下 循环判断 :
              判断 n 最右一位是否为 1 ,根据结果计数。
              将 n 右移一位

算法流程:
      初始化数量统计变量 count = 0 。
      循环逐位判断: 当 n = 0 时跳出。
            若 n&1=1 ,则统计数 count 加一。
            n >>= 1 : 将二进制数字 n 无符号右移一位 。
     返回统计数量 count 。

class Solution {
public:
    int hammingWeight(uint32_t n) 
    {
        // 逐位判断 (判断最右边位是否为1,并右移一位,将出现的1累加起来)
        if(n == 0) return 0;
        int count = 0;
       
       // 每次循环都判断最右边位是否为1,并右移一位,将出现的1累加起来。直到n=0,循环终止
        while(n != 0)
        {
            if((n & 1) == 1) count++;
            n >>= 1;
        }
        return count;
    }
};

位运算(& flag)

基本思路:                                                                                                                                   

1、将 n 与 flag=1(0001) 做 & 运算,判断 n 的最低位是否为 1,如果是1,计数器 count 加1
2、将 flag 左移一位得到 falg=2(0010),与 n 进行位与运算来判断 n 的后一位是否为1
3、重复上述步骤1→2,直到通过 flag 判断完整数 n 所有位是否为 1 为止。

class Solution {
public:
    int hammingWeight(uint32_t n) 
    {
        if(n == 0) return 0;
        // 把n和1做运算,判断n的最低位是不是1,
        // 接着把1左移一位得到2,再和n做运算,就能判断n的次低位是不是1
        int count = 0;
        unsigned int flag = 1;
        while (flag)
        {
            if (n & flag) count++;
            flag = flag << 1;
        }
        return count;
    }
};

位运算优化
思路及解法: 观察这个运算:n & (n−1),其预算结果恰为把 n 的二进制位中的最低位的 1 变为 0

         (n - 1)解析: 二进制数字 n 最右边的 1 变成 0 ,此 1 右边的 0 都变成 1 。
         n&(n−1) 解析: 二进制数字 n 最右边的 1 变成 0,其余不变。

class Solution {
public:
    int hammingWeight(uint32_t n) 
    {
        // 巧用n&(n-1) (将n最右边的1置0,在n=0之前 该操作的次数即为1的个数
        if(n == 0) return 0;
        int count = 0;
        // 每次循环都将n最右边的1置0,累加次数。直到所有1都置为0时,循环终止
        while(n)
        {
            n = n & (n-1);
            count++;
        }
        return count;
    }
};

循环检查二进制位

思路及解法:可以直接循环检查给定整数 n 的二进制位的每一位是否为 1。                                 

具体代码中,当检查第 i 位时,我们可以让 n 与 2^i(1 << i) 进行与运算,当且仅当 n 的第 i 位为 11 时,运算结果不为 0。

class Solution {
public:
    int hammingWeight(uint32_t n) 
    {
        if(n == 0) return 0;
        int count = 0;
        for(int i=0;i<32;i++)
        {
            if(n & (1 << i)) count++;
        }
        return count;
    }
};

扩展话题
1、用一条语句判断一个整数是不是2的整数次方,把这个整数减去1之后再和它自己做与运算,这个整数中唯一的1就会变成0 (n > 0 && (n & (n - 1)) == 0)
2、输入两个整数 m 和 n ,计算需要改变 m 的二进制表示中的多少个位才能得到 n ?思路就2步:
       求这两个数的异或
       统计异或结果中1的位数
举例来说,10的二进制表示为1010,13的二进制表示为1101,需要改变3位,也就是(0111中1的个数,而0111是1010和1101异或的结果)

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到