剑指offer-二进制中1的个数

除法运算效率较低,所以在编程中,尽可能地用移位来代替除法。

这个题目中的

class Solution {
public:
     int  NumberOf1_dead(int num) 
     {
         if(num == 0) return 0;
         
         int cnt = 0;
         while(num >= 1)
         {
             //if(num % 2 != 0) 比较低效,用位运算
             if(num & 1 != 0)
                 cnt ++;
             // num /= 2;低效
             num = num >> 1;
         }
     }
    
     int  NumberOf1_flag(int num) 
     {
         if(num == 0) return 0;
         
         int cnt = 0;
         unsigned int flag = 1; //这里使用unsigned int 类型
         //while(flag >= 1) 会存在flag为负的情况,
         while(flag >= 1)
         {
             //if(num & flag != 0) 这里不能这么写,&的优先级低于 !=
             if((num & flag) != 0)
                 cnt ++;
             flag = flag << 1;
         }
         
         return cnt;
     }    
    
     int  NumberOf1(int num) 
     {
         if(num == 0) return 0;
         
         int cnt = 0;
         while(num)
         {
             cnt ++;
             num = (num - 1) & num;
         }
         
         return cnt;
     }       
};

这里的判断不能写为if(num & flag != 0),因为&的优先级低于!=

这里num = (num - 1) & num;的思路会带来惊喜,但不容易想到。

num-1相当于

  • 当最低位是1,num-1就相当于去反操作,num由1变成了0,之前的所有位都保持不变;
  • 当最低位是0,假设最右边的1位于第m位,num-1后,第m位由1变成0,而第m位之后所有0都变成了1,而第m位之前的所有位都保持不变。

通过上面两种情况分析,获知,num-1都是把最右边的1变成0,而左边的都保持不变。

所以,num & (num-1)相当于把 num 最右边的1变成0。
eg: 判断n = 1100有几个1
n = 1100 & (1100-1) = 1100 & 1011 = 1000
n = 1000 & (1000-1) = 0111 & 1000 = 0

两次循环就结束了,速度非常快。

时间复杂度:O(n) n为val中1的个数
空间复杂度:O(1)

num & (num-1)相当于把 num 最右边的1变成0。,很多二进制问题都可以用这个思路解决。

eg:

  • 一个整数是不是2的整数次方
  • 输入两个整数m、n,赍需要改变m的二进制表示中的多少位才能得到n
    • 1.求这两个数的异或
    • 2.统计异或结果中1的位数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值