【來源】編程之美
【問題描述】前面的文章介紹瞭如何用較低的時間複雜度,求解一個二進制數中1 的個數。但是時間複雜度仍然是log2(n),其中n表示整數形式,log2(n)表示該整數用二進制表示需要的位數。即,不管二進制位是0還是1都要進行判斷,若二進制數特別大,這樣效率仍然不高。如何進一步提高效率。
【解題】我們只關注的是二進制數中1的個數,那麼我們就數一數1的個數0不用管。可是我們怎麼知道1的個數。設整數v,那麼我們採用位操作,v&(v-1),可以將最低位的1變爲0,消去最低位的1,這樣我們逐個的消除二進制數中1,所有的操作僅與1的個數有關,與0的個數無關。時間複雜度進一步降低。
程序描述如下:
int Count(int v)
{
int num =0;
while(v)
{
v &= (v-1);
num++;
}
return num;
}
【進一步】以上操作已經是時間複雜度降到很低了,那還有沒有更低的呢?
想一想,若僅是讓你求解一個8位二進制數1的個數,以上操作有點“大動干戈”了,8位二進制數,只有256種可能整數,我們完全可以用枚舉的方式列舉出來。
若給出的數是0 ,那麼沒有1,若是1、2、4、8、16、32、64、128則只有1個1……也就那麼9種可能:0個1,1個1,2個1,...,8個1,完全用if-else或者switch-case結構完成。代碼就不列舉了。表面上看起來應該比上面的算法要快,但是想一想,這麼多判斷語句也是消耗時間的,所以平均效率也不如前面的。
【空間換時間】有個聰明人想到了另外一種方法---hash映射。我們將整數與其二進制形式中1的個數做映射,知道了整數值直接可以得出1的個數,hash真的很強大。
這是不是很複雜的結構,我們僅需要用一個數組就能搞定。代碼省略。