別人家的面試題:統計“1”的個數

十年蹤跡發表於2016-05-27

小鬍子哥 @Barret李靖 給我推薦了一個寫演算法刷題的地方 leetcode.com,沒有 ACM 那麼難,但題目很有趣。而且據說這些題目都來源於一些公司的面試題。好吧,解解別人公司的面試題其實很好玩,既能整理思路鍛鍊能力,又不用擔心漏題 ╮(╯▽╰)╭。

長話短說,讓我們來看一道題

統計“1”的個數

給定一個非負整數 num,對於任意 i,0 ≤ i ≤ num,計算 i 的值對應的二進位制數中 “1” 的個數,將這些結果返回為一個陣列。

例如:

當 num = 5 時,返回值為 [0,1,1,2,1,2]。

解題思路

這道題咋一看還挺簡單的,無非是:

  • 實現一個方法 countBit,對任意非負整數 n,計算它的二進位制數中“1”的個數
  • 迴圈 i 從 0 到 num,求 countBit(i),將值放在陣列中返回。

JavaScript中,計算 countBit 可以取巧:

上面的程式碼裡,我們直接對 n 用 toString(2) 轉成二進位制表示的字串,然後去掉其中的0,剩下的就是“1”的個數。

然後,我們寫一下完整的程式:

版本1

上面這種寫法十分討巧,好處是 countBit 利用 JavaScript 語言特性實現得十分簡潔,壞處是如果將來要將它改寫成其他語言的版本,就有可能懵B了,它不是很通用,而且它的效能還取決於 Number.prototype.toString(2) 和 String.prototype.replace 的實現。

所以為了追求更好的寫法,我們有必要考慮一下 countBit 的通用實現法。

我們說,求一個整數的二進位制表示中 “1” 的個數,最普通的當然是一個 O(logN) 的方法:

所以我們有了版本2

這麼實現也很簡潔不是嗎?但是這麼實現是否最優?建議此處思考10秒鐘再往下看。


更快的 countBit

上一個版本的 countBit 的時間複雜度已經是 O(logN) 了,難道還可以更快嗎?當然是可以的,我們不需要去判斷每一位是不是“1”,也能知道 n 的二進位制中有幾個“1”。

有一個訣竅,是基於以下一個定律:

  • 對於任意 n, n ≥ 1,有如下等式成立:

這個很容易理解,大家只要想一下,對於任意 n,n – 1 的二進位制數表示正好是 n 的二進位制數的最末一個“1”退位,因此 n & n – 1 正好將 n 的最末一位“1”消去,例如:

  • 6 的二進位制數是 110, 5 = 6 – 1 的二進位制數是 101,6 & 5 的二進位制數是 110 & 101 == 100
  • 88 的二進位制數是 1011000,87 = 88 – 1 的二進位制數是 1010111,88 & 87 的二進位制數是 1011000 & 1010111 == 1010000

於是,我們有了一個更快的演算法:

版本3

上面的 countBit(88) 只迴圈 3 次,而“版本2”的 countBit(88) 卻需要迴圈 7 次。

優化到了這個程度,是不是一切都結束了呢?從演算法上來說似乎已經是極致了?真的嗎?再給大家 30 秒時間思考一下,然後再往下看。


countBits 的時間複雜度

考慮 countBits, 上面的演算法:

  • “版本1” 的時間複雜度是 O(N*M),M 取決於 Number.prototype.toString 和 String.prototype.replace 的複雜度。
  • “版本2” 的時間複雜度是 O(N*logN)
  • “版本3” 的時間複雜度是 O(N*M),M 是 N 的二進位制數中的“1”的個數,介於 1 ~ logN 之間。

上面三個版本的 countBits 的時間複雜度都大於 O(N)。那麼有沒有時間複雜度 O(N) 的演算法呢?

實際上,“版本3”已經為我們提示了答案,答案就在上面的那個定律裡,我把那個等式再寫一遍:

也就是說,如果我們知道了 countBit(n & (n - 1)),那麼我們也就知道了 countBit(n)

而我們知道 countBit(0) 的值是 0,於是,我們可以很簡單的遞推:

版本4

原來就這麼簡單,你想到了嗎 ╮(╯▽╰)╭

以上就是所有的內容,簡單的題目思考起來很有意思吧?程式設計師就應該追求完美的演算法,不是嗎?

這是 leetcode 演算法面試題系列的第一期,下一期我們討論另外一道題,這道題也很有趣:判斷一個非負整數是否是 4 的整數次方,別告訴我你用迴圈,想想更巧妙的辦法吧~

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

別人家的面試題:統計“1”的個數 別人家的面試題:統計“1”的個數

相關文章