面试题14:剪绳子
题目要求:
实现一个函数,输入一个int型整数,输出该数字在计算机中二进制表示形式的1的个数。例如9->1001,输出2;-3->11111111111111111111111111111101,输出31。
解题思路:
考查位运算,此题要注意负数的处理。首先要明确计算机中,数字是以补码的形式存储的,原码反码补码不清楚的话请自己谷歌百度。其次,明确位运算符,与&,或|,非~,异或^,<<左移位,>>带符号右移位,>>>无符号右移位(java有此符号,c++没有)
- 解法一:将数字无符号右移,直到为0。
- 解法二:使用一个标记,初始为1,让标记值与原输入数字异或,然后标记值左移。解法一是原数字右移,而解法二是标记左移,从java来看思路类似但换了个角度;但这个思路在C++就很关键,因为C++中没有>>>运算符,只能用解法二。
- 解法三:没接触过的人应该会觉得比较新颖。对于二进制数有如下结论:【把一个整数减去1之后再和原来的整数做位与运算,得到的结果相当于把原整数的二进制表示形式的最右边的1变成0】。比如1001,执行一次上述结论,1001&1000=1000,将最右边的1改为了0;再执行一次,1000&0111=0000,第二个1也改成了0。因此能执行几次该结论,就有几个1。对于解法一二,都需要循环32次,判断每一个比特位是否为1,而解法三,循环次数等于比特位为1的个数。时间上是有改进的。
package chapter2;
/**
* Created by ryder on 2017/7/6.
* 二进制中的1的个数
*/
public class P100_NumberOf1InBinary {
public static int numberOfOne1(int n){
int count=0;
while(n!=0){
if((n&1)!=0)
count++;
n>>>=1;
}
return count;
}
public static int numberOfOne2(int n){
int count=0;
int flag=1;
while(flag!=0){
if((n&flag)!=0)
count++;
flag<<=1;
}
return count;
}
public static int numberOfOne3(int n){
int count=0;
while(n!=0){
n = n&(n-1);
count++;
}
return count;
}
public static void main(String[] args){
System.out.println(numberOfOne1(3));
System.out.println(numberOfOne1(-3));
System.out.println(numberOfOne2(3));
System.out.println(numberOfOne2(-3));
System.out.println(numberOfOne3(3));
System.out.println(numberOfOne3(-3));
}
}
运行结果
2
31
2
31
2
31
其他相关
- 使用一条语句判断一个正整数是不是2的整数次方
public static boolean isPowerOfTwo(int n){
return (n&(n-1))==0;
}
- 输入两个整数m,n,计算最少需要改变m的多少位才能得到n
先对m,n进行异或,再统计异或结果中1的位数