劍指offer---二進制中1的個數

劍指offer—二進制中1的個數

問題分析

本題是爲了求解一個整數的二進制中1的個數。比如9(1001),它的二進制數就有兩個1。
這類的題目大部分都會用到位運算的知識,位運算非常抽象,而且在日常的生活中很少碰到,但是位運算的核心很簡單,因爲位運算的種類就那麼幾個(或、與、非、異或、左移和右移),所以只要將這些基本的操作熟記於心,這類的題目就好做了。
回到上面這題。第一種解法就是不斷的將這個數進行右移操做,直到這個數變爲零,每次檢查最低爲是否爲1,如果爲1,那麼1的個數就加1。比如9,右移的操作結果分別爲1001 >> 100 >> 10 >> 1 >> 0,只有1001和1末位爲1,只有這兩個數與1做與運算結果爲1,所以結果爲2。
細心的同學很快就會發現,如果給的數是一個是負數,那麼右移的話每次都會在左邊補1,那這樣就陷入了一個死循環中,程序出錯。

下面是第二個方法,既然題目所給的數在移位的時候可能會是負數,進而出現死循環,那麼我們是否可以找一個不會出現死循環的數?在上面的每次移位後都會與1進行與運算,就是用“1”來檢測每一位是否是1,既然這樣那麼可不可以讓“1”移動呢?當然可以的,我們可以讓1不斷的左移,這樣就不斷的在右邊補零。開始將1設爲unsigned int,所以右移32位後,就會變成0,這樣就可以作爲一個循環停止的條件。

第二種解答會執行32次操作,這樣來做還是有點多。既然所給的數的二進制中1的個數有限,那麼能不能每一次操作都能“剝離”一個1呢?這種解法相比較前面的兩個方法要複雜一點,要對位運算具有很好的理解。首先,當給定的數不爲0時,說明二進制中含有1,先將1的次數加上1,接下來將給的數減1。減1後有一個效果就是從右往左的第一個1變成0,1右邊的0全部變爲1,左邊的1和0保持不變。接下來就是與運算上場了,這兩個數直接相與,那麼原來右往左的第一個1以及後面的數全部都變成了0,至此就完成了1的“剝離”(如9的1001和1000相與結果爲1000,“剝離”了一個1)!後面就是循環操作相與後結果,直至結果變爲0。

源碼

// 第二種解法
int numbersOfOneNormalVer(int number){
	int count = 0;
	unsigned int flag = 1;
	while (flag){
		if (number & flag)
			count += 1;
		flag <<= 1;
	}

	return count;
}

// 第三種解法
int numbersOfOneSpecialVer(int number){
	int count = 0;
	while (number){
		++count;
		number &= (number - 1);
	}

	return count;
}

謝謝

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章