編程之美-2.1-求二進制數中1的個數

題目:對於一個字節的無符號整形變量,求其二進制表示中“1”的個數,要求算法的執行效率儘可能高。


剛看到這個題,首先想到的就是對二進制數進行向移位操作,看末位是不是1。這個即爲書中給出的第二種方案:

/* 方案2,移位操作*/ 
int Count(BYTE v){
    int num = 0;
    while(v){
        num += v & 0x01; //與000000001進行與操作,結果爲1說明末位爲1,num+1 
        v >>= 1;         //v向右移1位,直到變爲全0 
    }
} 

該方案與方案1的核心思想差不多,用BYTE v去除以2,就是向右移1位,餘數即爲移出的位是0還是1,如果移出是1,則num+1。這種移位思想,算法複雜度爲O(log2v),即v的二進制表示的位數,如果v爲10000000,就比較糟糕了,要算8次才能算完。如果複雜度只與v中的1的數量相關,就會好很多。

想到之前做的題目中http://blog.csdn.net/kimili1987/article/details/8034466,有一個是怎麼判斷一個數是2^n,事實上,這個數就是隻有一個1。方法是,對於數v,判斷v & (v-1)是否爲0,爲0的話則證明有一個1。據此進行擴展,如果有多個1的話,可以逐次使用該方法進行判斷,每次會削減掉v中最高位的1,直至最後v爲0,判斷的次數則爲總的1的數量。

/*方案3,判斷1的數量*/
int Count(BYTE v){
    int num=0;
    while(v){
        v &= (v-1);     //每次與v-1做與操作,削減掉最高位的1 
        num ++;
    }
} 

方案5的思路很有意思,因爲只是一個BYTE的整數,範圍爲0~255,索性預存一個256個數的數組countTable[256],保存每個數對應的1的個數會是多少,例如countTable[8]=3,然後直接返回countTable[v]就可以得到1的個數了。時間複雜度O(1),空間複雜度是最高的O(256)。這是一個典型的空間換時間的算法,實現雖簡單,但是其給出的思想很重要:可以通過犧牲一定的空間,來換取高的時間效率!

擴展問題:

擴展問題1:如果變量v變爲32位DWORD,那麼使用哪種方案?

對於擴展問題1,當v變爲DWORD的時候,方法5可能不太合適了,需要空間過於龐大。而方案3依舊非常適合。這一點也說明了一個算法對於輸入數據的適應性問題。根據算法複雜度對哪些變量敏感,不同的算法對輸入數據的適應性有所不同。

擴展問題2:給定兩個正整數A,B。判斷A和B中有多少位是不同的?

1)最直接的方式,A和B每一位都做異或操作,如果爲1,num+1,複雜度O(較大位數{A,B})。

2)對A和B做異或,之後再數其中1的數量,Count(A ^ B),複雜度O(1+A和B位數不同的數量)。


這是編程之美書中指出的一個童鞋給出的更好的一些解法

http://blog.csdn.net/justpub/article/details/2292823


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