剑指Offer:二进制中1的个数Java/Python

1.题目描述

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

2.算法描述

2.1.知识补充

首先明确下整数的在计算机中是如何存储的。在计算机中用0表示 + + +,1表示 − -
整数的二进制形式,比如 1 2 10 = 110 0 2 12_{10}=1100_{2} 1210=11002 − 1 2 10 = − 110 0 2 -12_{10}=-1100_{2} 1210=11002
那在计算机中12与-12如何存储的呢?
他们都是以补码的形式存储的,我们以32位计算机为例。

正整数的原码符号位是0,符号位与最高数字位之间补0,反码与补码和原码一样:

[ 12 ] 原 = 00000000000000000000000000001100 [12]_{原}=00000000000000000000000000001100 [12]=00000000000000000000000000001100
[ 12 ] 反 = 00000000000000000000000000001100 [12]_{反}=00000000000000000000000000001100 [12]=00000000000000000000000000001100
[ 12 ] 补 = 00000000000000000000000000001100 [12]_{补}=00000000000000000000000000001100 [12]=00000000000000000000000000001100

负整数的原码符号位是1,符号位与最高数字位之间补0,对原码除了符号位,取反得到反码,然后加1得到补码:(至于为什么这样,去看计算机组成原理,总之为了方便计算机操作)

[ − 12 ] 原 = 10000000000000000000000000001100 [-12]_{原}=10000000000000000000000000001100 [12]=10000000000000000000000000001100
[ − 12 ] 反 = 11111111111111111111111111110011 [-12]_{反}=11111111111111111111111111110011 [12]=11111111111111111111111111110011
[ − 12 ] 补 = 11111111111111111111111111110100 [-12]_{补}=11111111111111111111111111110100 [12]=11111111111111111111111111110100

2.2.求解算法

很容易想到的方法是对该整数和1做&运算,然后进行右移。比如12的补码,确实可以正确得到。但是-12就不正确了,当对一个负数右移的时候,会一直在最高位补1,这样就会陷入死循环。
正确的思路:

1.一个二进制数减1之后,会得到什么?(不用管是补码还是什么,补码不就是个二进制数嘛)

会把这个二进制数从右往左遇到第一个1之前的所有0都会变为1,而将遇到的第一个1变为0。本质来说,会把 从 右 往 左 遇 到 第 一 个 1 的 那 段 二 进 制 数 取 反 \red{从右往左遇到第一个1的那段二进制数取反} 1。比如:12和-12
00000000000000000000000000001 100 \red{100} 100 - 1 = 00000000000000000000000000001 011 \red{011} 011
11111111111111111111111111110 100 \red{100} 100 - 1 = 11111111111111111111111111110 011 \red{011} 011

2.一个二进制数和这个二进制数减1后的二进制数做&运算会得到什么?

会把这个二进制数从右往左遇到的第一个1变为0,本质来说, 就 是 将 最 右 边 的 1 变 为 0 \red{就是将最右边的1变为0} 10
00000000000000000000000000001 100 \red{100} 100&00000000000000000000000000001 011 \red{011} 011 = 00000000000000000000000000001 000 \red{000} 000
11111111111111111111111111110 100 \red{100} 100&11111111111111111111111111110 011 \red{011} 011 = 11111111111111111111111111110 000 \red{000} 000

3.我们重复做1,2的操作,在这个二进制数变为0前可以做多少次这样的操作,是不是就说明这个二进制数中有多少个1了?

3.代码描述

3.1.Java代码

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

3.2.Python代码

#Python的负数是无限精度的,如果是负数,相当于有无限个1,所以需要与32个1相与,特殊处理
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        ans = 0
        if n<0:
            n =  n & 0xffffffff 
        while n:
            n = n & (n-1)
            ans += 1
        return ans
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值