大多數的讀者都會有這樣的反應:這個題目也太簡單了吧,解法似乎也相當地單一,不會有太多的曲折分析或者峰迴路轉之處。那麼面試者到底能用這個題目考察我們什麼呢?事實上,在編寫程式的過程中,根據實際應用的不同,對儲存空間或效率的要求也不一樣。比如在
pc上的程式編寫與在嵌入式裝置上的程式編寫就有很大的差別。我們可以仔細思索一下如何才能使效率盡可能地「高」。 【
解法一】
可以舉乙個八位的二進位制例子來進行分析。對於二進位制操作,我們知道,除以乙個
2,原來的數字將會減少乙個
0。如果除的過程中有餘,那麼就表示當前位置有乙個1。
以10 100 010
為例;
第一次除以
2時,商為
1 010 001
,余為0。
第二次除以
2時,商為
101 000
,余為1。
因此,可以考慮利用整型資料除法的特點,通過相除和判斷餘數的值來進行分析。於是有了如下的**。
**int count(int v)
v = v/ 2;
}return num;}
【解法二
】使用位操作
前面的**看起來比較複雜。我們知道,向右移位操作同樣也可以達到相除的目的。唯一不同之處在於,移位之後如何來判斷是否有
1存在。對於這個問題,再來看看乙個八位的數字:
10 100 001。
在向右移位的過程中,我們會把最後一位直接丟棄。因此,需要判斷最後一位是否為
1,而「與」操作可以達到目的。可以把這個八位的數字與
00000001
進行「與」操作。如果結果為
1,則表示當前八位數的最後一位為
1,否則為
0。**如下: **
int count(int v)
return num;}
【解法三】
位操作比除、餘操作的效率高了很多。但是,即使採用位操作,時間複雜度仍為o(
log2v),
log2
v為二進位制數的位數。那麼,還能不能再降低一些複雜度呢?如果有辦法讓演算法的複雜度只與「
1」的個數有關,複雜度不就能進一步降低了嗎?
同樣用10 100 001
來舉例。如果只考慮和
1的個數相關,那麼,我們是否能夠在每次判斷中,僅與
1來進行判斷呢?
為了簡化這個問題,我們考慮只有乙個
1的情況。例如:
01 000 000。
如何判斷給定的二進位制數裡面有且僅有乙個
1呢?可以通過判斷這個數是否是
2的整數次冪來實現。另外,如果只和這乙個「
1」進行判斷,如何設計操作呢?我們知道的是,如果進行這個操作,結果為0或為
1,就可以得到結論。
如果希望操作後的結果為0,
01 000 000
可以和00 111 111
進行「與」操作。
這樣,要進行的操作就是
01 000 000 &
(01 000 000
–00 000 001
)= 01 000 000 &
00 111 111 = 0。
因此就有了解法三的**: **
int count(int v)
return num;}
【解法四
】使用分支操作
解法三的複雜度降低到o(
m),其中m是
v中1的個數,可能會有人已經很滿足了,只用計算
1的位數,這樣應該夠快了吧。然而我們說既然只有八位資料,索性直接把
0~255
的情況都羅列出來,並使用分支操作,可以得到答案,**如下: **
int count(int v)
return num;}
解法四看似很直接,但實際執行效率可能會低於解法二和解法三,因為分支語句的執**況要看具體位元組的值,如果
a =0
,那自然在第1個
case
就得出了答案,但是如果
a =255
,則要在最後乙個
case
才得出答案,即在進行了
255次比較操作之後!
看來,解法四不可取!但是解法四提供了乙個思路,就是採用空間換時間的方法,羅列並直接給出值。如果需要快速地得到結果,可以利用空間或利用已知結論。這就好比已經知道計算
1+2+
… +n
的公式,在程式實現中就可以利用公式得到結論。
最後,得到解法五:演算法中不需要進行任何的比較便可直接返回答案,這個解法在時間複雜度上應該能夠讓人高山仰止了。
【解法五
】查表法
**/*
預定義的結果表*/
int counttable[256] =
;int count(int v)
這是個典型的空間換時間的演算法,把
0~255中「1
」的個數直接儲存在陣列中,
v作為陣列的下標,
counttable[v]就是v
中「1」的個數。演算法的時間複雜度僅為o(
1)。在乙個需要頻繁使用這個演算法的應用中,通過「空間換時間」來獲取高的時間效率是乙個常用的方法,具體的演算法還應針對不同應用進行優化。
1.如果變數是
32位的
dword
,你會使用上述的哪乙個演算法,或者改進哪乙個演算法? 2.
另乙個相關的問題,給定兩個正整數(二進位制形式表示)a和
b,問把a變為
b需要改變多少位(
bit)?也就是說,整數a 和
b 的二進位制表示中有多少位是不同的?
相關資源:
《程式設計之美》編輯部
|
《程式設計之美》豆瓣
|
《程式設計之美》互動網購買
|
作者blog
作者豆瓣
求二進位制中1的個數
在 程式設計之美 一書中有一節提到如何求乙個位元組的無符號整型變數二進位制表示中中1的個數,主要提到了四種方法。下面簡單介紹一下 1.求餘法 在將十進位制數轉換為二進位制數時,採用除2取餘法。將每次除2得到的餘數儲存起來逆序輸出便是該十進位制整數的二進位制表示。因此可以採用這種方法去統計1的個數。i...
求二進位制中1的個數
解法有很多種 以乙個位元組無符號位元組變數作為例子 解法一 求餘法 在將十進位制數轉換為二進位制數時,採用除2取餘法。將每次除2得到的餘數儲存起來逆序輸出便是該十進位制整數的二進位制表示。因此可以採用這種方法去統計1的個數。public int count byte n return sum 解法二...
求二進位制中1的個數
這是乙個經常會在筆試和面試中遇到的題目,今天我做到了這個題目,就來分享一下我對這個題目的解決思路。首先拿到這個題目,我們的基本思路是 先判斷最後一位是否為1,接著把數字依次右移,判斷每一位是否為1,直到整數變為0為止。基於這個思路我們可以寫下如下的 int count int n n n 1 ret...