動機
這題會不會太過分
Problem
Given a positive integer n
, return the number of the integers in the range [0, n]
whose binary representations do not contain consecutive ones.
Example 1:
Input: n = 5Output: 5Explanation:Here are the non-negative integers <= 5 with their corresponding binary representations:0 : 01 : 12 : 103 : 114 : 1005 : 101Among them, only integer 3 disobeys the rule (two consecutive ones) and the other 5 satisfy the rule.
Example 2:
Input: n = 1Output: 2
Example 3:
Input: n = 2Output: 3
Constraints:
1 <= n <= 109
Sol
原本是給一個dp,用奇偶去刷出後面違法的數字,但要alloc很大的mem,大概到10^8就很慢,10^9直接死亡
class Solution {
public:
int findIntegers(int n) {
int ret = 1;
bool* dp = new bool[n+1];
memset(dp,0,sizeof(bool)*(n+1));
for(auto i=1;i<=n;i++) {
if(dp[i]) {
for (auto now = (i << 1);now <= n;now <<= 1)
dp[now] = dp[now+1 < n+1 ? now+1 : now] = 1;
} else {
if (i%2 == 1){
for (auto now = (i << 1)|1;now <= n;now = ((now<<1)|1))
dp[now] = 1;
}
ret++;
}
}
return ret;
}
};
假設f(n)
是n位數的所有沒有連續1的總數
如果n是5,11111 ~ 00000 就會是
- 10 111 ~ 10 000
- f(3)
- 0 1111 ~ 0 0000
- f(4)
這兩種組合,11 111 ~ 11 000就會出事就不用考慮,01 111 ~ 01 000會被0 1111 ~ 0 0000包含
而這就是fib的遞迴模式
所以要做的是,從最高位往下加所有組合,同時看有沒有11出現,有就後面不用算了 順利走完代表數字本身是ok的,故回傳之前要加1
class Solution:
def findIntegers(self, n: int) -> int:
@cache
def fib(n):
if n == 0:
return 1
elif n == 1:
return 2
else:
return fib(n-1)+fib(n-2)
ret, pre0 = 0, False
for k in reversed(range(32)):
if (n & (1 << k)): # k+1 == 目前最高位長度
ret += fib(k)
if pre0:
return ret
else:
pre0 = True
else:
pre0 = False
return ret+1 # 能跑出loop就是沒有Consecutive Ones