剑指offer11--二进制1的个数

题目描述

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

思路

首先可以利用原码反码补码的知识直接暴力求解。
源码:首位为符号位,正0负1,后面为真值(绝对值)
反码:正数等于原码,负数除了符号位其余取反
补码:正数等于原码,负数为反码+1

当输入为正数时,直接除2取余法;
当输入为负数时,根据补码和源码的关系来转化成正数。
例如:对于一个8位数,符号位占1位,

补码1000 0001-11000 1001-9
反码1000 00001000 1000
原码1111 1111-1271111 0111-119

补码与原码绝对值相加得到128,即2^7。因此输入一个负数,用128相加得到一个正数,例如-119+128=9,1共有2个,再加上符号位一共是3位。
同理,对于一个32位数,除去符号位,还有31个有效位数,即用2^31去与负数相加。

实现

class Solution {
public:
     int  NumberOf1(int n) {
         if (n==0) return 0;
         int ret=0;
         if (n>0)
         {
             int m=0;
             while (n!=0)
             {
                 m=n%2;
                 n/=2;
                 if (m!=0) ret++;
             }
         }
         else
         {
             ret=NumberOf1(2147483648+n)+1;//2^31相加,最后结果+1(符号位)
         }
         return ret;
     }
};

技巧

对于一个不为0的2进制数,肯定存在若干个1;当对其减1的时候,最右边的1变成0,这个1右边的0全变成1,相当于消掉了原来位置上的1,但是又引入了更多的1,那么如何解决这个引入的问题?只需要跟原来的数做与运算,例如:
1100-1=
1011 再与
1000 这样就消去了最右边的1
如此循环减1下去,直到为0
循环次数即等于1的个数
实现

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

知识点

原码反码补码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值