本文參考自《劍指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),須要注意一下