题目描述
输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
解题思路
-
遇到的坑:
- int的位数,即该用多长的数组去存储二进制位。
- Int16: -32768(-216)到 +32767 (216-1)之间的有符号整数。
- Int32: -2,147,483,648(-232) 到 +2,147,483,647 (232-1)之间的有符号整数。
- Int64 :-9,223,372,036,854,775,808 (-264)到 +9,223,372,036,854,775,807(264-1) 之间的整数。
- long long能表示264个数,因为要考虑正负数,所以是 -263~ (263-1)。
- int是32位整数,上限是 (231-1),下限是 -231
- 当int值时-2,147,483,648时,其原码是1000 0000 0000 0000 0000 0000 0000 0000, 反码是:1111 1111 1111 1111 1111 1111 1111 1111,补码是1000 0000 0000 0000 0000 0000 0000 0000,在求补码时产生了溢出。
-
逻辑:
- 正负数处理逻辑不一样,分开讨论。
- 声明32位数组,将其初始化为1,第一步用来存放反码(由while循环实现)。
- 为了防止在循环中产生溢出(针对-2,147,483,648),需要在while循环结束后再将符号位置为1。
- for循环中+1求补码(不对符号位进行操作),求补码的同时记录补码中1的个数。
代码
public class Solution {
public int NumberOf1(int n) {
int count = 0;
if(n >= 0){
while( n != 0){
if(n % 2 == 1){
count++;
}
n = n /2;
}
} else {
count++;
int arr[] = new int[32];
for(int i = 1;i<arr.length;i++){
arr[i] = 1;
}
int index = arr.length - 1;
while( n != 0){
if((-1) * (n % 2) == 0){
arr[index--] = 1;
} else {
arr[index--] = 0;
}
n = n /2;
}
arr[0] = 1;
int num = 1;
for (int i = arr.length - 1; i > 0; i--){
if(arr[i] + num == 2){
arr[i] = 0;
num = 1;
} else if(arr[i] + num == 1){
arr[i] = 1;
count++;
num = 0;
}
}
}
return count;
}
}
和同事讨论后的代码
巧妙地利用移位的办法和n做与运算,如果该位是0,则与的结果是0。
public int NumberOf1(int n) {
int count = 0, i = 0;
while(i <32){
if(((1 << i) & n) != 0){
count++;
}
i++;
}
return count;
}
补充说明
对于一个int n,通过下述办法可以求得其二进制
int count = 0, i = 0;
while(i <32){
System.out.println(n >> i & 1);
i++;
}