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}
就是将最右边的1变为0。
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