Google面試題 | 不包含連續1的非負整數

九章演算法發表於2017-08-17

專欄 | 九章演算法
網址 | www.jiuzhang.com

題目描述

給定一個正整數n,求出0到n中有幾個數滿足其二進位制表示不包含連續的1。1<=n<=10^9。

樣例

輸入:5
輸出:5
說明:0到5的二進位制表示分別為:
0 : 0
1 : 1
2 : 10
3 : 11
4 : 100
5 : 101
這六個數中,只有3的二進位制表示包含有連續的1,故答案為5。

解題思路分析

暴力方法:列舉0到n,判斷其二進位制是否包含連續的1,時間複雜度為O(n*log(n)),對於題目的n的範圍來說比較大。

考慮一種比較簡單的情況,如果n=2^k - 1,其中k為正整數,那麼問題就變成二進位制數00……0(k個0)到11……1(k個1)中有幾個數不包含連續的1,設答案為f(k)。

我們可以考慮k位二進位制數的第一位:如果第一位是0,那麼第二位既可以取0也可以取1,也就是說對後面的k-1位無影響,所以第一位為0的滿足條件的數總共有f(k-1)個;如果第一位是1,那麼由於不能出現連續的1,第二位只能取0,但是對後面的k-2位無影響,所以第一位為1的滿足條件的數總共有f(k-2)個。

這樣,我們就得到了:f(k) = f(k-1) + f(k-2)。邊界條件為f(1)=2以及f(2)=3,由於f(0)=1滿足原問題的題意也滿足上述的轉移方程,故可以取邊界條件f(0)=1,f(1)=2。

對於n不是2^k-1的一般情況,與上一點的不同之處在於:上一點中只要滿足二進位制位長度不超過k,那麼這個數就不會超過n=2^k - 1,而這種情況需要具體考慮不超過n的數。

假設n的二進位制有k位,最高位為1,其二進位制為1xx……x(x表示0或1),那麼0到n可分為00……0(k個0)到011……1(一個0,k-1個1)和100……0(一個1,k-1個0)到1xx……x(即n)兩個部分。

前一個部分即0到2^(k-1)-1,這部分中滿足條件的答案為f(k-1);第二部分則需進一步討論:如果n的二進位制從左往右第二位為1,即n的形式為11x……x,那麼因為題目要求不能有連續的1,所以這一位只能取0,這樣的數一定小於n,所以後k-2位不受大小的限制,答案為f(k-2),並結束計算;如果n的二進位制從左往右第二位為0,即n的形式為10x……x,那麼為滿足不超過n的條件,第二位也只能取0,這樣問題就變為從100……0到10x……x之間有多少滿足條件的數,這樣就可以繼續對n的二進位制的後k-2位進一步進行類似的討論。

舉個例子,n=10,二進位制為1010:

對於最高位的1,我們將0到1010分為0到111和1000到1010兩部分,前一部分的個數為f(3) = 5。

第二部分為1000到1010,最高位確定取1,而n的二進位制從左往右第二位為0,為滿足不超過n的條件,滿足條件的數從左往右第二位只能取0。

n的二進位制從左往右第三位為1,這樣我們又可以按i中的方法,把1000到1010再次分成1000到1001和1010兩個部分,前一部分的個數為f(1) = 2。

到n的最低位,為0,故最後一位只能取0,按照之前的演算法這一步不會增加答案,但由於n=1010b本身還沒有計入,故再加1。

最後得到答案5+2+1=8。

n的二進位制長度為log(n),故該演算法的時間複雜度為O(log(n))。

參考程式

www.jiuzhang.com/solution/no…

面試官角度分析

這道題考察位運算的基本知識和動態規劃的思想,難點在於如何原本的逐個統計問題通過二進位制分類統計,屬於面試中中等難度的題目。給出正確的解法可以達到hire。

lintcode相關問題

www.lintcode.com/zh-cn/probl…


推薦閱讀:



歡迎關注我的微信公眾號:九章演算法(ninechapter)。
精英程式設計師交流社群,定期釋出面試題、面試技巧、求職資訊等

九章演算法,IT教育領域的深耕者
九章演算法,IT教育領域的深耕者

相關文章