[LeetCode] Non-negative Integers without Consecutive Ones 非負整數不包括連續的1
Given a positive integer n, find the number of non-negative integers less than or equal to n, whose binary representations do NOT contain consecutive ones.
Example 1:
Input: 5 Output: 5 Explanation: Here are the non-negative integers <= 5 with their corresponding binary representations: 0 : 0 1 : 1 2 : 10 3 : 11 4 : 100 5 : 101 Among them, only integer 3 disobeys the rule (two consecutive ones) and the other 5 satisfy the rule.
Note: 1 <= n <= 109
這道題給了我們一個數字,讓我們求不大於這個數字的所有數字中,其二進位制的表示形式中沒有連續1的個數。根據題目中的例子也不難理解題意。我們首先來考慮二進位制的情況,對於1來說,有0和1兩種,對於11來說,有00,01,10,三種情況,那麼有沒有規律可尋呢,其實是有的,我們可以參見這個帖子,這樣我們就可以通過DP的方法求出長度為k的二進位制數的無連續1的數字個數。由於題目給我們的並不是一個二進位制數的長度,而是一個二進位制數,比如100,如果我們按長度為3的情況計算無連續1點個數個數,就會多計算101這種情況。所以我們的目標是要將大於num的情況去掉。下面從頭來分析程式碼,首先我們要把十進位制數轉為二進位制數,將二進位制數存在一個字串中,並統計字串的長度。然後我們利用
解法一:
class Solution { public: int findIntegers(int num) { int cnt = 0, n = num; string t = ""; while (n > 0) { ++cnt; t += (n & 1) ? "1" : "0"; n >>= 1; } vector<int> zero(cnt), one(cnt); zero[0] = 1; one[0] = 1; for (int i = 1; i < cnt; ++i) { zero[i] = zero[i - 1] + one[i - 1]; one[i] = zero[i - 1]; } int res = zero[cnt - 1] + one[cnt - 1]; for (int i = cnt - 2; i >= 0; --i) { if (t[i] == '1' && t[i + 1] == '1') break; if (t[i] == '0' && t[i + 1] == '0') res -= one[i]; } return res; } };
下面這種解法其實蠻有意思的,其實長度為k的二進位制數字符串沒有連續的1的個數是一個斐波那契數列f(k)。比如當k=5時,二進位制數的範圍是00000-11111,我們可以將其分為兩個部分,00000-01111和10000-10111,因為任何大於11000的數字都是不成立的,因為有開頭已經有了兩個連續1。而我們發現其實00000-01111就是f(4),而10000-10111就是f(3),所以f(5) = f(4) + f(3),這就是一個斐波那契數列啦。那麼我們要做的首先就是建立一個這個陣列,方便之後直接查值。我們從給定數字的最高位開始遍歷,如果某一位是1,後面有k位,就加上f(k),因為如果我們把當前位變成0,那麼後面k位就可以直接從斐波那契數列中取值了。然後標記pre為1,再往下遍歷,如果遇到0位,則pre標記為0。如果當前位是1,pre也是1,那麼直接返回結果。最後迴圈退出後我們要加上數字本身這種情況,參見程式碼如下:
解法二:
class Solution { public: int findIntegers(int num) { int res = 0, k = 31, pre = 0; vector<int> f(32, 0); f[0] = 1; f[1] = 2; for (int i = 2; i < 31; ++i) { f[i] = f[i - 2] + f[i - 1]; } while (k >= 0) { if (num & (1 << k)) { res += f[k]; if (pre) return res; pre = 1; } else pre = 0; --k; } return res + 1; } };
類似題目:
參考資料: