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
Review:
有两种解法,一种用到数学归纳法,还有一种是纯逻辑
- 数学归纳
n = 1,2.....31
定义f(n) 为 2^(n-1)到0中的不含连续1的个数
f(1) = 1
f(2) = 2
f(3) = 3
f(4) = 5
f(5) = 8 ...
(斐波那契数列)
其中 f(3) = f(2)+f(1) , f(4) = f(3)+f(2) , f(5) = f(4)+f(3)
假设 f(n) = f(n-1) + f(n-2) 当 n=31时 f(n) = f(n-1) + f(n-2) 也成立
由此我们可以得到一个字典数组,2^m m∈{0,1,2,...,30} (int最大32位,而第32位是符号位) 对应有多少不含连续的数
我们求一个正整数到0有多少个不含连续1的数只需要求出对应位为1时不含连续1的数的总和
贴一下代码
class Solution {
public int findIntegers(int num) {
//斐波那契数列
int[] rec ={1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711
,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309};
int res = 1,i=31;
boolean flag = false;
while (i--!=0){
int step = 1<<i;
if ((num & step)==step){
res+=rec[i];
if (flag){
res --;
break;
}
flag = true;
}else {
flag = false;
}
}
return res;
}
}
不过使用这种数学归纳法总归是不严谨的(其实上述关系可以使用逻辑证明,只不过博主水平有限)
我们可以反过来,用一种比较好理解的方式来递推,依然可以使用常数级的计算次数得出答案
f(x)为2^(n-1)到0中含连续1的数的个数
即推导f(n) = 2^(n-3)+f(n-1)+f(n-2)
虽然看起来比上一个复杂点,但是容易理解
贴一下代码
class Solution {
static final int[] data = new int[31];
static {
data[2]=1;
data[3]=3;
int flag = 4;
for (int i = 4; i < 31; i++) {
data[i] = flag + data[i-1] + data[i-2];
flag<<=1;
}
}
public int findIntegers(int num) {
int result = 0;
boolean flag = false;
for (int i = 30; i > -1; i--) {
int step = 1<<i;
if ((num & step)==step){
result+=data[i];
if (flag){
result += (num & (step-1))+1;
break;
}
flag = true;
}else {
flag = false;
}
}
return num+1-result;
}
}