Number of Digit One

【题目来源】

233. Number of Digit OneAC代码

【分析】

5 5 位数X7429为例,其中 X X 可取19 len=5 len = 5 为该数字的长度

首先考虑最高位(万位)上 1 1 出现的次数

  1. X=1,则从 1000017429 10000 – 17429 ,共 7430 7430 次,这个次数可以通过除去 X X 之后的数字7429 1 1 得到

  2. X>1,则从 1000019999 10000 – 19999 ,共 10len=10000 10 len = 10000

    if( first == 1 )
        result += stoi( str.substr( 1, len - 1 ) ) + 1;
    else if( first > 1 )
        result += (int)( pow( 10, len - 1 ) );

    然后考虑出现在非最高位上 1 1 出现的次数

    X=3为例, 37429 37429

    划分为 4 4 个区间,17429 743017429 7430 – 17429 1743027429 17430 – 27429 2743037429 27430 – 37429
    1 1 个区间长度为7429,剩余区间长度均为 10000 10000

    对于第 1 1 个区间,1出现的次数可以通过递归调用得到

    result += helper( str.substr( 1, len - 1 ) );

    对于第 2 2 个区间743017429,共包含 10000 10000 个数,除去万位,构成了从 0000 0000 9999 9999 的完整循环
    于是统计从 0000 0000 9999 9999 这个序列中 1 1 出现的次数:1可以出现在 4 4 个位置(千位、百位、十位、个位),每个位置共出现了103次(剩下 3 3 个位置,每个位置都可以取09,即 10×10×10 10 × 10 × 10
    统计结果:从 0000 0000 9999 9999 的序列中 1 1 出现的次数为4×103

    更一般化的表达式为 (len1)×10len2 ( len − 1 ) × 10 len − 2 ,这个式子对于剩下2个区间仍然成立

    于是 X=3 X = 3 时,共有 3 3 个区间,非最高位的1出现的次数为 X×(len1)×10len2 X × ( len − 1 ) × 10 len − 2

    result += first * (len - 1) * (int)( pow( 10, len - 2 ) );

    【AC代码】

    class Solution {
    public:
        int countDigitOne(int n) {
            // 测试样例有负数,答案为0
            if( n < 0 )
                return 0;
    
            return helper( to_string(n) );
        }
    
        int helper( string str )
        {
            int len = str.length();
            int first = str[0] - '0';   // first为数字的最高位
    
            // 递归终止条件
            if( len == 1 )
                return first == 0 ? 0 : 1;
    
            int result = 0;
    
            // 最高位
            if( first == 1 )
                result += stoi( str.substr( 1, len - 1 ) ) + 1;
            else if( first > 1 )
                result += (int)( pow( 10, len - 1 ) );
    
            // 非最高位
            result += helper( str.substr( 1, len - 1 ) );
            result += first * (len - 1) * (int)( pow( 10, len - 2 ) );
    
            return result;
        }
    };
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值