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 <= 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;
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值