第十五周:( LeetCode600) Non-negative Integers without Consecutive Ones(c++)

来源:互联网 发布:淘宝 冰毒 编辑:程序博客网 时间:2024/06/05 00:14

原题:
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

思路:本题用到的算法思想包括动态规划和分治,涉及到十进制和二进制的相互转化。以下算法时间复杂度为o(logn),过程有一点点繁琐但应该比较好理解,可能会有更简洁的思路。下面就简述一下我的思路吧。

首先,题目的大意是,给定一个正整数n,求小于等于n的非负整数,其二进制数不存在连续1的数的个数。
比如:n=5,那么小于等于5的非负整数一共有6个:
0 : 0
1 : 1
2 : 10
3 : 11
4 : 100
5 : 101
其中,只有 3(11)存在着连续1,所以结果为6-1=5。

下面以n=30(11110)为例,简述我的思路。首先把小于等于11110的数分成三段来算:(1)sum1(0-1111)(2)sum2(10000-10111)(3)sum3(11000-11110)。

(1)计算sum1。可以看到,sum1中涉及到的数为:
一位:0 1
两位:10 11
三位:100 101 (110 111)
四位:1000 1001 1010 1011 (1100 1101 1110 1111 )
我们用dp[i]来表示位数为i的那些数中有存在连续1的数的个数。明显地有,比如在dp[4]中,后一半的数(括号内,即1100 1101 1110 1111 ),都以“11”开头。这部分的数为2^(i-2)个;前一半的数(即1000 1001 1010 1011),都以“10”开头,所以前两位没有出现连续1,这部分的数出现连续1要看后面两位数的情况,也就是dp[i-2]。所以,可以推出,dp[i]=dp[i-2]+2^(i-2)。用sum[i]来表示小于等于i位数的数的个数。sum[4]=sum[3]+dp[4]。即sum[i]=sum[i-1]+dp[i]。这样,我们就完成了sum1的计算。

(2)计算sum2。可以看到,sum2中的数以“10”开头,所以前两位不存在连续1,所以其实也就是算从000-111中,存在连续1的数的个数,其实也就是(1)中的sum[3]。

(3)计算sum3。可以看到,sum3中,所有的数都以“11”开头,所以都符合要求,所以sum3=(11110-11000+1)。

这样,我们就完成了n=30(11110)的计算,如果n=22(11110),只需分成两部分的计算:(1)sum1(0-1111)(2)sum2(10000-10110)。情况会略有不同,代码中会给出这种情况的计算方法。

代码如下:

class Solution {public:    //计算2的n次方       int pow2(int pow){        int res=1;        for(int i=0;i<pow;i++)            res*=2;        return res;    }    //十进制转为二进制    vector<int> DecimaltoBinary(int Decimal){        vector<int> Binary;        while(Decimal){            Binary.insert(Binary.begin(),Decimal%2);            Decimal/=2;        }        return Binary;    }    //二进制转为十进制    int BinarytoDecimal(vector<int> & Binary){        int Decimal=0;        for(int i=0;i<Binary.size();i++)            Decimal+=(pow2(Binary.size()-i-1)*Binary[i]);        return Decimal;    }    int step(int num,int res,int dp[],int sum[]){        //num小于4(二进制数位数小于三位)的情况直接return        if((num==0)||(num==1)||(num==2))            return res;        if(num==3)            return res+1;        int sum1;        vector<int> Binary;        Binary=DecimaltoBinary(num);        sum1=sum[Binary.size()-1];        if(Binary[1]==1){            //"11"开头的数的情况            //删除前两位            Binary.erase(Binary.begin());            Binary.erase(Binary.begin());            //res=sum2+sum3+sum1            res+=(sum[Binary.size()]+(BinarytoDecimal(Binary)+1)+sum1);        }else{            //"10"开头的数的情况            //删除前两位            Binary.erase(Binary.begin());            Binary.erase(Binary.begin());            //res=sum2+sum1            res+=(step(BinarytoDecimal(Binary),res,dp,sum)+sum1);        }        return res;    }    int findIntegers(int num){        //res记录出现连续1的数的个数        int res=0;        //初始化dp[]、sum[]        int dp[32],sum[32];        dp[1]=0;dp[2]=1;        sum[1]=0;sum[2]=1;        for(int i=3;i<32;i++){            dp[i]=sum[i-2]+pow2(i-2);            sum[i]=dp[i]+sum[i-1];        }        return num+1-step(num,res,dp,sum);    }};
阅读全文
1 0