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

本文介绍了一种高效算法,用于计算任意整数(包括负数)的二进制表示中1的个数。通过巧妙利用二进制运算性质,避免了传统右移操作在负数情况下的无限循环问题。

1.题目描述

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

2.算法描述

2.1.知识补充

首先明确下整数的在计算机中是如何存储的。在计算机中用0表示+++,1表示−-
整数的二进制形式,比如1210=1100212_{10}=1100_{2}1210=11002−1210=−11002-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
00000000000000000000000000001100\red{100}100 - 1 = 00000000000000000000000000001011\red{011}011
11111111111111111111111111110100\red{100}100 - 1 = 11111111111111111111111111110011\red{011}011

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

会把这个二进制数从右往左遇到的第一个1变为0,本质来说,就是将最右边的1变为0\red{就是将最右边的1变为0}10
00000000000000000000000000001100\red{100}100&00000000000000000000000000001011\red{011}011 = 00000000000000000000000000001000\red{000}000
11111111111111111111111111110100\red{100}100&11111111111111111111111111110011\red{011}011 = 11111111111111111111111111110000\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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值