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}就是将最右边的1变为0。
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
本文介绍了一种高效算法,用于计算任意整数(包括负数)的二进制表示中1的个数。通过巧妙利用二进制运算性质,避免了传统右移操作在负数情况下的无限循环问题。

332

被折叠的 条评论
为什么被折叠?



