剑指 Offer 43. 1~n整数中1出现的次数

输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。

例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。

示例 1:

输入:n = 12
输出:5
示例 2:

输入:n = 13
输出:6

限制:

1 <= n < 2^31

解:
eg: 对于整数64012

思路:分别计算,0~64012,所有个位出现的1的次数 + 十位出现的1的次数 + ……

将一个数分为high cur low ,

640 1 2,计算十位出现1的次数;
对于high∈[0,639],十位为1的数为10~19,1共64010次;
对于high = 640,十位为1的数字10,11,12,1共3次;
故总值为640
10 + 2 + 1。

64 0 12,计算百位出现的1的次数;
对于high∈[0,63],百位为1的数为100~199,1共64100次;
对于high = 64,不存在百位为1的数字;
故总值为64
100。

6 4 012,计算千位出现的1的次数;
对于high∈[0,5],千位为1的数为1000~1990,1共6*1000次;
对于high = 6,千位为1的数为1000~1990,1共1000次;
故总值为(6+1)*100。

总结:
当cur = 0,cnt = high*(10^位数)
当cur = 1,cnt = high*(10^位数) + low + 1
当cur > 1,cnt = (high + 1)(10^位数)

时间复杂度分析
循环内部时间复杂度为O(1),循环次数为n的十进制位数,log(10)n,故时间复杂度为O(logn)。

class Solution {
public:
    int countDigitOne(int n) {

        int res = 0;
        int low = 0,high = n/10,cur = n%10;
        unsigned int digit = 1;//(10^位数,2的31次方是十位数,故digit最大为10^10,int型会溢出)
        while(high != 0 || cur != 0)
        {
            if(cur == 0) res += high*digit;
            else if(cur == 1) res += high*digit + low + 1;
            else res += (high + 1)*digit;

            low += cur*digit;
            digit *= 10;
            cur = high%10;
            high /= 10;
        }        
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值