zoukankan      html  css  js  c++  java
  • Leetcode 600.不包含连续1的非负整数

    不包含连续1的非负整数

    给定一个正整数 n,找出小于或等于 n 的非负整数中,其二进制表示不包含 连续的1 的个数。

    示例 1:

    输入: 5

    输出: 5

    解释:

    下面是带有相应二进制表示的非负整数<= 5:

    0 : 0

    1 : 1

    2 : 10

    3 : 11

    4 : 100

    5 : 101

    其中,只有整数3违反规则(有两个连续的1),其他5个满足规则。

    说明: 1 <= n <= 109

    思路

    考虑一种比较简单的情况,如果n=2^k - 1,其中k为正整数,那么问题就变成二进制数00……0(k个0)到11……1(k个1)中有几个数不包含连续的1,设答案为f(k)。

    我们可以考虑k位二进制数的第一位:如果第一位是0,那么第二位既可以取0也可以取1,也就是说对后面的k-1位无影响,所以第一位为0的满足条件的数总共有f(k-1)个;如果第一位是1,那么由于不能出现连续的1,第二位只能取0,但是对后面的k-2位无影响,所以第一位为1的满足条件的数总共有f(k-2)个。

    这样,我们就得到了:f(k) = f(k-1) + f(k-2)。边界条件为f(1)=2以及f(2)=3,由于f(0)=1满足原问题的题意也满足上述的转移方程,故可以取边界条件f(0)=1,f(1)=2。

    对于n不是2^k-1的一般情况,与上一点的不同之处在于:上一点中只要满足二进制位长度不超过k,那么这个数就不会超过n=2^k - 1,而这种情况需要具体考虑不超过n的数。

    假设n的二进制有k位,最高位为1,其二进制为1xx……x(x表示0或1),那么0到n可分为00……0(k个0)到011……1(一个0,k-1个1)和100……0(一个1,k-1个0)到1xx……x(即n)两个部分。

    前一个部分即0到2^(k-1)-1,这部分中满足条件的答案为f(k-1);第二部分则需进一步讨论:如果n的二进制从左往右第二位为1,即n的形式为11x……x,那么因为题目要求不能有连续的1,所以这一位只能取0,这样的数一定小于n,所以后k-2位不受大小的限制,答案为f(k-2),并结束计算;如果n的二进制从左往右第二位为0,即n的形式为10x……x,那么为满足不超过n的条件,第二位也只能取0,这样问题就变为从100……0到10x……x之间有多少满足条件的数,这样就可以继续对n的二进制的后k-2位进一步进行类似的讨论。

    举个例子,n=10,二进制为1010:

    对于最高位的1,我们将0到1010分为0到111和1000到1010两部分,前一部分的个数为f(3) = 5。

    第二部分为1000到1010,最高位确定取1,而n的二进制从左往右第二位为0,为满足不超过n的条件,满足条件的数从左往右第二位只能取0。

    n的二进制从左往右第三位为1,这样我们又可以按i中的方法,把1000到1010再次分成1000到1001和1010两个部分,前一部分的个数为f(1) = 2。

    到n的最低位,为0,故最后一位只能取0,按照之前的算法这一步不会增加答案,但由于n=1010b本身还没有计入,故再加1。

    最后得到答案5+2+1=8。

    n的二进制长度为log(n),故该算法的时间复杂度为O(log(n))。

    第一种情况示意

    第二种情况示意:

     

     1 class Solution {
     2     public int findIntegers(int num) {
     3         if(num==0) return 1;
     4         String binary = Integer.toBinaryString(num);
     5         int len=binary.length();
     6         int[] f = new int[len+1];
     7         f[0]=1;
     8         f[1]=2;
     9         //计算场i的二进制位符合要求的个数
    10         for(int i=2; i<=len; i++) {
    11             f[i] = f[i-1]+f[i-2];
    12         }
    13         //计算0~n的符合要求的总个数
    14         int sum=0;
    15         for(int i=0, k=len; i<len; i++,k--) {
    16             if(binary.charAt(i)=='1') {
    17                 sum+=f[k-1];
    18                 if(i>0 && binary.charAt(i-1)=='1') {
    19                     return sum;
    20                 }
    21             }
    22         }
    23         //先前没有return,到这里,说明n本身没有算进去
    24         sum++;
    25         return sum;
    26     }
    27 }
  • 相关阅读:
    容斥原理
    m元集A到n元集B的满射的个数
    二项式反演公式
    多项式定理
    组合数的基本性质
    Luogu P2408 不同子串个数
    Luogu P5410【模板】扩展 KMP
    Luogu P2336 [SCOI2012]喵星球上的点名
    Luogu P2852 [USACO06DEC]牛奶模式Milk Patterns
    Luogu P4248 [AHOI2013]差异
  • 原文地址:https://www.cnblogs.com/kexinxin/p/10381413.html
Copyright © 2011-2022 走看看