题目
输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示。
思路
输出了一个32位二进制的数。说明,暗含的说明了,取值范围在4个字节。那么在4个字节,就可以用int类型去接受这样一个整数。
十进制转二进制,我们用除2再取出余数进行获取1的个数。
-
关于正数
我们可以直接对其进行计算。动态获取,无需存储。
优化: 运用移位运算符。- 右移1位相当于除以2 右移2位除以4
- 左移1位等于乘2 左移2位等于乘4
样例
int n = 8;
// 计算8位的二进制
for(int i = 7;i >= 0;i--) {
System.out.print((n >> i) & 1 );
}
- 关于负数
我们需要对其进行转换一下。因为我们的所有数据在计算机底层是以补码的形式,那么有的人就会问了为什么正数,不需要?因为正数的原、反、补是一模一样的。- 原码 —> 反码(除了符号位不变其余取反) —> 补码(反码 + 1)
- 因此,对于负数的产生我们需要用一个容器进行一个存储,因为后面需要对反码 + 1
AC代码
import java.util.Stack;
public class Solution {
public int NumberOf1(int n) {
int sum = 0;
if(n > 0) {
while(n > 0) {
if(n % 2 == 1)
sum++;
n = n / 2;
}
}else if(n == 0) {
return sum;
}else {
// 先让他变成正数。
n = 0 - n;
// 因为,我们都知道,十进制转二进制。
// 先计算出来的值。其实在后面。因此用到了堆栈
Stack<Integer> s = new Stack();
while(n > 0) {
s.push((n % 2));
n = n / 2;
}
int t = s.size();
// 为了考虑到 整数最小的时候。会产生溢出。因此数组长度为:33
int[] a = new int[33];
// 初始化。符号位和溢出位
a[0] = 0;
a[1] = 1;
// 原码
for(int i = 32 - t + 1 ; i <= 32 ; i++) {
a[i] = s.pop();
}
// 反码。除了符号位,其他为全取反
for(int i = 2;i <= 32 ; i++) {
if(a[i] == 1)
a[i] = 0;
else
a[i] = 1;
}
// 补码。反码 + 1
// 偷了一个懒。数最后一个0的位置。0的位置置1。后面的置0
t = 32;
// 1 + 1 = 10
// 本位:0
// 进位:1
while(true) {
if(a[t] == 0) {
a[t] = 1;
break;
}
a[t] = 0;
t--;
}
// 数1的个数
// 注意:整数最小值的时候。符号位会产生进位。
// 个人觉得,理论上不应该加上最后的进位。因为如果算上就是33个二进制数了
for(int i = 0; i <= 32;i++) {
if(a[i] == 1)
sum++;
}
//System.out.println(Arrays.toString(a));
}
return sum;
}
}