页码统计

牛牛新买了一本算法书,算法书一共有n页,页码从1到n。牛牛于是想了一个算法题目:在这本算法书页码中0~9每个数字分别出现了多少次? 
统计在1-n个数字中,0、1、2、3……9各出现了多少次
首先简化,判断1-n个数字中,i出现的次数,0<=i <=9。
//计算1-n的整数中,i出现的次数
int nCount(int n, int i)
{
    int num = 0;
    for ( int temp =1; temp <=n; temp++) {
        int tt = temp;
        while (tt !=0) {
            if (tt % 10 == i) {
                num++;
            }
            tt/=10;
            if (tt == 0) {
                continue;
            }
        }
    }
    return  num;
}
int main(int argc, const char * argv[]) {
    // insert code here...
    int n;
    while (cin >>n) {
        for (int i=0; i<9; i++) {
            cout << nCount(n, i) << " ";
        }
        cout << nCount(n, 9);
    }
    return 0;
}
以上方法时间复杂度非常大,无法满足要求。
根据编程之美所说,对于一个n位数m,要统计1-m中数字1出现的次数,就依次判断n位中每一位是1分别有多少情况,加起来就是总的次数。
比如数123,是个3位数。为别统计个位为1,十位为1,百位为1的数各有多少,加起来就是1-123中出现1的次数。
每一位为1的数量,与他的高位、低位有关。
int cal(int page, int data)
{
    int num =0;
    int temp =1;
    int low = 0;  //记录当前位的低位
    int orig = page;
    
    while (page != 0) {
        if (page % 10 > data)
        {
            num += (page/10+1)*temp;
        }
        else if (page % 10 < data)
        {
            num += (page/10)*temp;
        }
        else
        {
            num += (page/10)*temp + (low+1);
        }
        temp *= 10;
        low = orig - (orig/temp)*temp;
        page /= 10;
    }
    return num;
}

以上只使用于统计1-9出现的次数,因为没有比0还小的数,所以上述方法的第一种情况不适用于统计0出现的
int cal0(int page)
{
    int num =0;
    int temp =1;
    int low = 0;
    int orig = page;
    
    while (page != 0) {
        if (page % 10 == 0) {
            num += (page/10 -1)*temp + (low +1);
        }
        else
        {
            num += (page /10)*temp;
        }
        temp *= 10;
        low = orig - (orig/temp)*temp;
        page /= 10;
        
    }
    return num;
}
所以综上
int main(int argc, const char * argv[]) {
    // insert code here...
    int n;
    while (cin >>n) {
        cout << cal0(n);
        for (int i=1; i <10; i++) {
            cout << " " << cal(n, i);
        }
    }
    return 0;
}

顺利通过!



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值