剑指 Offer 15. 二进制中1的个数
请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如,把 9 表示成二进制是 1001,有 2 位是 1。因此,如果输入 9,则该函数输出 2。
小试牛刀一:存取二进制
博主刚开始看到这个题时以为传进去的n是十进制所以整道题需要以下三步
1.十进制转换为二进制,存取余的值
2.倒序输出存的取余结果
3.与1比较
现在想想其实不用倒序,因为不管是正序还是倒序1的个数是确定的,因为思考到十进制转二进制需要除二取余然后倒序排列,所以博主想到了栈这个数据结构,先push进去余数,再pop出来就是我们所需的顺序。当然如果你需要输出二进制的结果一定要记得顺序,数组remainderArray存的是十进制转二进制的结果。
还要注意的是十进制转二进制时先获得余数
public static int hamming(int n) {
//先转为二进制,除二取余,倒序排列
int count = 0;
Stack<Integer> remainder = new Stack<>();
while(n != 0){
//余数存入栈
remainder.push(n%2);
n = n/2;
}
int size = remainder.size();
int[] remainderArray = new int[size];
//出栈,遍历找为1
for(int i = 0; i < size; i++){
remainderArray[i] = remainder.pop();
if(remainderArray[i] == 1){
//使用count计数
count++;
}
}
return count;
//return count
}
在执行没有通过之后博主知道放入的应该是二进制的数据,就想到将数组转换为char类型的数组,遍历数组,当与’1’同时,count++,但是这样的方法在idea会自动转换为一个是进制的数据,也是不可以得到正确的结果,在leetcode里面也得不到正确的结果,不知道为什么?
public static int hammingWeight(int n){
String ns = String.valueOf(n);
char[] nc= ns.toCharArray();
int count = 0;
for(int i = 0; i < nc.length; i++){
if(nc[i] == '1'){
count++;
}
}
return count;
}
int型变量赋值为00000000000000000000000000001011不会越界吗?
并不会越界。int型变量占4个字节,一个字节8位,那么int型变量是32位的,范围是-2^31=-21 4748 3648 到 2^31-1=21 4748 3647。
int能表示的最大正整数为:
0111 1111 1111 1111 1111 1111 1111 1111 (最高位表示符号位,正数符号位为0)对应的10进制数为2^31-1=2147483647,对应的十六进制表示为:0x7FFFFFF
所以示例三的表示在idea里面会报错,超出int的范围
*为什么是521?
因为在数组的表示中0x表示十六进制,0表示八进制,0d表示二进制。所以00000000000000000000000000001011的八进制是521。再继续向下运算是都是按521的二进制进行运算的,521的二进制是1000001001
为什么下次循环是n是260?
因为& 和>>>都是二进制的运算,即1000001001的运算。&后count+1,>>>后1000001000的十进制是260
小试牛刀二:转换为char数组
为什么结果不对?
转为string类型的char[]存的是521,只会有一个1字符,这里并不清楚为什么leetcode编译出来了2,但idea编译出结果为1
其实在leetcode里面主要考查的是位运算符
方法一:逐位判断
当n&1时,末尾是0,结果是0;末尾是1,结果为1
再使用位运算将二进制后移逐位判断。
public int hammingWeightThree(int n){
int count = 0;
while(n != 0){
count += n & 1;
n >>>= 1;
}
return count;
}
方法二:巧用 n & (n - 1))
(n - 1) 解析: 二进制数字 n 最右边的 1变成 0,此 1右边的 00 都变成 1 。
n&(n−1) 解析: 二进制数字 n 最右边的 1变成 0 ,其余不变
.
public int hammingWeightTour(int n) {
int res = 0;
while(n != 0) {
res++;
n &= n - 1;
}
return res;
}
方法三:调用toBinaryString()转数字符串
在Integer类中有静态方法toBinaryString(int i)方法,此方法返回int变量的二进制表示的字符串。同理,Integer类中也提供了toHexString(int i)方法和toOctalString(int i)方法来分别返回int变量的16进制表示和8进制表示字符串。
下面是调用接口直接将int数据转换为二进制字符串,即将输入00000000000000000000000000001011八进制521转为二进制再进行之后的运算。
方法四:replaceAll直接用null替代0
public static int NumberOf1(int n) {
String A = Integer.toBinaryString(n).replaceAll("0", "");
return A.length();
}