本文参考自《剑指offer》一书,代码采用Java语言。html
更多:《剑指Offer》Java实现合集 java
请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如把9表示成二进制是1001,有2位是1。所以若是输入9,该函数输出2。面试
遇到与二进制有关的题目,应该想到位运算(与、或、异或、左移、右移)。ide
方法一:”与运算“有一个性质:经过与对应位上为1,其他位为0的数进行与运算,能够某一整数指定位上的值。这道题中,先把整数n与1作与运算,判断最低位是否为1;接着把1左移一位,与n作与运算,能够判断次低位是否为1……反复左移,便可对每个位置都进行判断,从而能够得到1的个数。这种方法须要循环判断32次。函数
方法二(better):若是一个整数不为0,把这个整数减1,那么原来处在整数最右边的1就会变为0,原来在1后面的全部的0都会变成1。其他全部位将不会受到影响。再把原来的整数和减去1以后的结果作与运算,从原来整数最右边一个1那一位开始全部位都会变成0。所以,把一个整数减1,再和原来的整数作与运算,会把该整数最右边的1变成0。这种方法,整数中有几个1,就只须要循环判断几回。post
测试用例测试
1.正数(包括边界值一、0x7FFFFFFF)url
2.负数(包括边界值0x80000000、0xFFFFFFFF)spa
3.0code
(含测试代码)
/** * * @Description 面试题15:二进制中1的个数 * * @author yongh * @date 2018年9月17日 下午3:01:16 */ // 题目:请实现一个函数,输入一个整数,输出该数二进制表示中1的个数。例如 // 把9表示成二进制是1001,有2位是1。所以若是输入9,该函数输出2。 public class NumberOf1InBinary { public int NumberOf1_Solution1(int n) { int count = 0; int flag = 1; while (flag != 0) { if ((flag & n) != 0) count++; flag = flag << 1; } return count; } public int NumberOf1_Solution2(int n) { int count = 0; while (n != 0) { count++; n = (n - 1) & n; } return count; } // =========测试代码========= void test(String testName, int n, int expected) { if (testName != null) System.out.println(testName + ":"); if (NumberOf1_Solution1(n) == expected) { System.out.print(" soluton1:" + "passed "); } else { System.out.print(" solution1:" + "failed "); } if (NumberOf1_Solution2(n) == expected) { System.out.println("soluton2:" + "passed "); } else { System.out.println("solution2:" + "failed "); } } void test1() { test("Test for 0", 0, 0); } void test2() { test("Test for 1", 1, 1); } void test3() { test("Test for 10", 10, 2); } void test4() { test("Test for 0x7FFFFFFF", 0x7FFFFFFF, 31); } void test5() { test("Test for 0xFFFFFFFF", 0xFFFFFFFF, 32); } void test6() { test("Test for 0x80000000", 0x80000000, 1); } public static void main(String[] args) { NumberOf1InBinary demo = new NumberOf1InBinary(); demo.test1(); demo.test2(); demo.test3(); demo.test4(); demo.test5(); demo.test6(); } }
Test for 0: soluton1:passed soluton2:passed Test for 1: soluton1:passed soluton2:passed Test for 10: soluton1:passed soluton2:passed Test for 0x7FFFFFFF: soluton1:passed soluton2:passed Test for 0xFFFFFFFF: soluton1:passed soluton2:passed Test for 0x80000000: soluton1:passed soluton2:passed
1.与二进制有关的题目要往位运算方面想,复习一下:二进制位运算的几个用法
2.注意:负数右移仍是负数!即若是对n=0x8000 0000右移,最高位的1是不会变的。若是这道题目经过令n=n>>1来计算n中1的个数,该数最终会变成0xFFFF FFFF而陷入死循环!
3.把一个整数减1,再和原来的整数作与运算,会把该整数最右边的1变成0。这种方法必定要紧紧记住,不少状况下均可能用到,例如:
1)一句话判断一个整数是否为2的整数次方;
2)对两个整数m和n,计算须要改变m二进制表示中的几位才能获得n。
4.与数字操做有关的题目,测试时注意边界值的问题。对于32位数字,其正数的边界值为一、0x7FFFFFFF,负数的边界值为0x80000000、0xFFFFFFFF。
5.几个细节问题
1)flag=flag<<1,而不是只写一句flag<<1;
2)flag&n!=0,而非flag&n==1; 也就不能写成count+=(flag&1)了
3)if语句中,不能写为if(flag&n!=0) ,而要写成 if((flag&n)!=0),须要注意一下