1. 程式人生 > >劍指Offer面試題10(Java版):二進位制中的1的個數

劍指Offer面試題10(Java版):二進位制中的1的個數

題目:請實現一個函式,輸入一個整數,輸出該數二進位制表示中1的個數。例如把9表示成二進位制是1001,有2位是1,因此如果輸入9,該函式輸出2.

1、可能引起死迴圈的解法

這是一道很基本的考察二進位制和位運算的面試題。題目不是很難,面試官提出問題之後,我們很快形成一個基本的思路:先判斷證書二進位制表示中最右邊一位是不是1.接著把輸入的證書右移一位,此時原來處於從右邊樹起的第二位被移到最後一位,再判斷是不是1.這樣沒移動一位,知道整個整數變成0為止。現在的問題變成怎麼判斷一個整數的最右邊是不是1了。這很簡單,只要把整數和1做位與運算看結果是不是0就知道了。1除了最右邊的一位之外所有的位都是0.基於這個思路,我們很快寫出這樣的程式碼:

int numberOf1(int n)

{

int count = 0;

while(n!=0){

if(n & 1)

count++;

n = n>>1;

}

return count;

}

面試官看了 程式碼後可能會問:把證書右移一位和把整數除以2在數學上是等價的,那上面的程式碼中可以把右移換成除以2嗎?答案是否定的。因為除法的效率比移位運算要低很多,在實際程式設計中應儘可能地用移位運算代替乘除法。

面試官會問第二個問題就是:上面的函式如果輸入一個負數,比如0x80000000,執行的時候會發生什麼情況呢?把負數0x80000000右移一位的時候,並不是簡單地把最高位的1移到第二位變成0x40000000,而是0xC0000000.這是因為移位前是個負數,仍然保證移位是個負數,因此移位後的最高位會設為1.如果一直做右移位運算,最終這個數字會程式設計0xFFFFFFFF而陷入死迴圈。

2、常規解法:

為了避免死迴圈,我們可以不右移輸入的數字n.首先把n和1做與運算,判斷n的最低位是不是1.接著把1左移一位得到2,再和n做與運算,就能判斷n的次低位是不是1。。。。這樣反覆左移,每次都能判斷n的其中一位是不是1.基於這種思路,我們可以寫出這樣的程式碼:

int number1(int n){

int count = 0;

int flag= 1;

while(flag ! =0){

if(n& flag)

count++;

flag =flag <<1;

}

return count;

}

這個解法中迴圈的次數等於二進位制中的位數,32位的整數需要迴圈32次,下面我們再介紹一個演算法,整數中有幾個1就只迴圈幾次。

3、能給面試官帶來驚喜的演算法。

我們的分析就是:把一個整數減去1,再和原整數做與運算,會把該整數最右邊的一個1變成0.那麼一個整數的二進位制表示中有多少個1,就可以進行多少次運算。基於這種思路,我們可以寫出這樣的程式碼:

/**
 *題目:實現一個函式,輸入一個整數,輸出該數二進位制表示中的1的個數。
 *例如把9改成二進位制是1001,有2位是1.因此如果輸入9,該函式輸出2. 
 */
package swordForOffer;

/**
 * @author JInShuangQi
 *
 *         2015年7月30日
 */
public class E10NumberOf1InBinary {
	public int numberOf1(int num) {
		int count = 0;
		while (num != 0) {
			count++;
			num = num & (num - 1);

		}
		return count;
	}

	public static void main(String[] args) {
		E10NumberOf1InBinary test = new E10NumberOf1InBinary();
		System.out.println(test.numberOf1(9));
	}
}