1的个数

int Count(unsigned int v)
{
    int num = 0;
    
    while(v)
    {
         v &= (v-1);
         num++;
    }
    return num;
}

这种方法速度比较快,其运算次数与输入n的大小无关,只与n中1的个数有关。如果n的二进制表示中有k个1,那么这个方法只需要循环k次即可。

其原理是不断清除n的二进制表示中最右边的1,同时计数器加1,直至n为0

对于int 型32位的呢

def NumberOf1( n):
    min_val=-2**31
    if n ==min_val:
        return 1
    if n>=0:
        num=0
    else:
        num=1
    while n!=0 and n>min_val:
        n&=n-1
        num+=1

    return num

 int型32位表示范围为-2^31~2^31-1,最高位表示符号位,负数比正数多一位,多的这以为就是100000000000000,就是-0,也就是-2^31。

在判断1的个数的时候,负数的符号位也为1,所以也要加入判断,所以如果n为负数,则初始化的时候,num=1

 

计算十进制数中1的个数

 给定一个数n,计算从1~n中所有数字中出现1的次数总和。

f(13)=6

f(23)=13

f(24)=14

通过分析发现:f(n)=个位出现1的次数+十位出现1的次数+百位出现1的次数+...

某一位出现1的个数总结,以十位为例

如果十位是0:以1101为列,十位出现1的个数10~19,110~119,210~219,...,910~919,1010~1019共计110个,说白了就是在十位出现1(10~19)的情况下,最高的两位可以不停的变化,从00~10,共00,01,02,..,10,共计11种情况,每种情况下都对应低位的(10~19)10个,所以共计110个出现1。总结为highNum*factor(如果是计算十位个数,factor=10,百位factor=100)

如果十位是1:同上分析,则为highNum*factor+lowerNum+1,多了一个低位数加1,就是既与高位数有关,也与低位数有关。

如果十位大于1:则为(highNum+1)*factor。

def sum1s(n):
    count=0
    factor=1
    while n//factor:
        lowerNum=n%factor
        currNum=(n//factor)%10
        highNum=n//(factor*10)
        if currNum==0:
            count+=highNum*factor
        elif currNum==1:
            count+=highNum*factor+lowerNum+1
        else:
            count+=(highNum+1)*factor
        factor*=10
    return count

 这样的话计算一个1~n数中,所有出现1的个数时间复杂度为O(log10(n)),也就是只与n的位数有关系了。

posted @ 2017-12-22 15:28  光彩照人  阅读(540)  评论(0编辑  收藏  举报