43.1~n整数中1出现的次数

43 1~n整数中1出现的次数

1 题目描述

​ 输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。

2 题目分析

求1-n整数中1出现的次数。这是个数学题,对于一个整数n,要找1~n所有的1,可以将某一位固定为1,然后找所有小于该数的排列组合,从最低位往最高位依次找,最终的结果就是1的总数了。
具体对于当前位有三种情况:cur = 0,cur = 1, cur > 1,还需要知道当前指向元素的数位digit(个/十/百...),以及高位大小high和低位的大小low
1. 当cur = 0时,如 1304,digit = 10,high = 13,low = 4,那么当前位为1的所有情况如下:
    [00-12]1[0-9]  // [00-12]表示高位所有的可能,1表示当前位,[0-9]表示低位所有的可能
    故此时1的个数count = high*digit
2. 当cur = 1时,如1314, digit = 10, high = 13, low = 4,那么当前位为1的所有情况如下:
    [00-12]1[0-9]和131[0-4]
    故此时1的个数count = high*digit + low + 1;
3. 当cur>1时,如1324, digit = 10, high = 13, low = 4,那么当前位为1的所有情况如下:
    [00-13]1[0-9]
    故此时1的个数count = (high + 1) * digit
    总结:
    初始从最低位开始,high = n / 10, low = 0, cur = n % 10, digit = 1;
    下一次各变量的状态为:high = high / 10, low = low + cur * digit, cur = high % 10, digit = digit * 10;
    终止条件:high和cur都为0,即循环条件为while(high != 0 || cur != 0):

    count = high * digit,  cur = 0;
    count = high * digit + low + 1,  cur = 1;
    count = (high + 1) * digit,  cur > 1;
    最后返回count的总和。

PS:有个更简单的规律公式,将i从1遍历到n,每次i扩大10倍:
(n/(i*10))表示(i*10)位上的个数;
min(max(n % (i*10)-i+1, 0), i)表示需要额外数的(i * 10)位上1的个数
例:1234
个位上1的数量 = 1234/10(对应1, 11, 21, ... 1221) + min(4, 1)(对应1231) = 124
十位上1的数量 = (1234/100) * 10(对应10,11,12,...110,111, 1919) + min(21, 10) (对应1210,1211,...1219) = 130
百位上1的数量 = (1234/1000)*100+min(135, 100)=200
千位上1的数量 = (1234 / 10000)*1000 + min(235, 1000)=235

3 代码

public int countDigitOne(int n) {
    // 初始化
    int cur = n % 10, high = n / 10, low = 0, digit = 1;
    int count = 0;
    while (high != 0 || cur != 0) {
        if (cur == 0) count += high * digit;
        else if (cur == 1) count += high * digit + low + 1;
        else count += (high + 1) * digit;

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值