Leetcode 600. Non-negative Integers without Consecutive Ones
Leetcode 600. Non-negative Integers without Consecutive Ones
題目:
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 <= 10^9
解法:
先理解一下題意:大概意思是說找一下小於等於 N 的數裡面有多少個數表示成二進位制形式之後,不會有連續的兩個 1 出現在其二進位制序列裡面。
先說一下我最開始的想法:
從 0 到 N 遍歷 N 個數字,將小於等於 N 的每一個數字用bitset
表示出來,然後用一個迴圈從bitset
的0位置開始將相鄰兩位相加,觀察結果是否會有 2 出現,如果出現就證明不滿足題意;如果遍歷完沒出現,就讓統計值 +1 ;
這種方法是可以求出最終結果的,但是會超時!所以直觀的方法行不通!
如圖:
另尋他路
在網上檢視大佬們的解題思路,有一種比較巧妙的方法介紹一下:
最後我們所要求的結果是:
total = a[i-1] + b[i-1]
( i 在這裡指數字轉二進位制後的長度)
但是我們使用的這種方法會有多算的情況,比如當我們輸入 8 或 9 時候,其二進位制長度都是 4 ,所以我們在計算小於等於 8 的滿足題意的數字的時候,可能會把 9 10 都算進去,所以我們要把多餘的情況減掉。
那具體應該怎麼減去這些數字?
假如我們要計算 num = 8 的情況,那麼當長度等於 4 時候,則 0、1、2、4、5、8共 6 個數字滿足題意,但是total = a[3]+b[3] = 8
,多餘的情況為 9 = 1001(2) 、10 = 1010(2) ;
我們演算法最初開始在生成二進位制數字時候,是逆序生成的,也即 8 = 0001 ,所以我們可以從待測序列的倒數第二位往前算
- 如果位置
j
和位置j+1
上的數字都是 0 ,那麼就在total
中減去b[j]
; - 如果位置
j
和位置j+1
上的數字都是 1 ,那麼直接退出
這裡之所以減去 b[j]
,因為在位置j
上可能會出現滿足題設要求的 1 ,而在 1 位置上滿足情況的個數為 b[j]
程式碼:
class Solution
{
public:
int findIntegers(int num)
{
int n = num;
string t = "";
while (n > 0)
{
t += (n & 1) == 1 ? "1" : "0";
n = n >> 1;
}
vector<int> zero(t.length() , 0), one(t.length(), 0);
zero[0] = one[0] = 1;
for (int i = 1; i < t.length(); i++)
{
zero[i] = zero[i - 1] + one[i -1];
one[i] = zero[i - 1];
}
int res = zero[t.length() - 1] + one[t.length() - 1];
for (int i = t.length() - 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;
}
};