[美团笔试算法题] 统计位数

14 篇文章 0 订阅
10 篇文章 1 订阅
题目
统计位数
  • 题目描述:求数字n以内的正整数有多少位数字,不统计前导零。例如n=13时,13以内的正整数有12345678910111213,一共17位,则输出17
  • 输入:

    • 第一行一个数 T (T<=100),表述数据组数。
    • 对于每组数据,第一行1个整数n,(1<=n<=10^9)
  • 输出:

    • 对于每组输出,输出一行,表示数字位数和。
  • 样例输入:

2
13
4
  • 样例输出:
17
4
解题思路
  1. 没有思路时,归纳:( f(n) f ( n ) 表示n的统计位数)
    • 如果 n9 n ≤ 9 ,则很简单,位数和就是n: f(n)=n f ( n ) = n
    • 如果 n[10,99] n ∈ [ 10 , 99 ] ,位数和为 (n9)×2+9 ( n − 9 ) × 2 + 9 : f(n)=(n9)×2+f(9) f ( n ) = ( n − 9 ) × 2 + f ( 9 )
    • 如果 n[100,999] n ∈ [ 100 , 999 ] ,位数和为 (n99)×3+(9910)×2+9 ( n − 99 ) × 3 + ( 99 − 10 ) × 2 + 9 : f(n)=(n99)×3+f(99) f ( n ) = ( n − 99 ) × 3 + f ( 99 )
  2. 规律基本出来了,
    f(n)=(n10K1+1)K+f(10K11) f ( n ) = ( n − 10 K − 1 + 1 ) ∗ K + f ( 10 K − 1 − 1 ) , if 10K1<n10K,that is K=floor(log10n) if   10 K − 1 < n ≤ 10 K , that is  K = floor ( log 10 ⁡ n )

  3. 需要注意的点

    • 题中给出了n的限制: 1n109 1 ≤ n ≤ 10 9
代码
  1. 非递归
#include  <iostream> 
using namespace std;

int main()
{
    int a, b, T;
    long int tab[10]={0, 9, 9+90*2, 9+90*2+900*3, 9+90*2+900*3+9000*4, 9+90*2+900*3+9000*4+90000*5,
               9+90*2+900*3+9000*4+90000*5+900000*6, 9+90*2+900*3+9000*4+90000*5+900000*6+9000000*7,
               9+90*2+900*3+9000*4+90000*5+900000*6+9000000*7+90000000*8,
        9+90*2+900*3+9000*4+90000l*5+900000*6+9000000*7+90000000*8+900000000*9l 
    };//9l, the 'l' is important
    long int tab1[10]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
    cin>>T;
    for(int i=0;i<T;i++)
    {
        cin>>a;
        int K=9;
        while(a<tab1[K])
        {
            cout<<tab[K]<<endl;  //for debug
            K--;    
        }
        cout<<tab[K]+(a-tab1[K]+1)*(K+1)<<endl;

    }
    return 0;
}
  1. 递归
#include  <iostream> 
#include  <cmath>
using namespace std;

unsigned long int my_pow_10(unsigned int k)
{
    unsigned long int tab[10]={1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};
    if(k<=9)
    {
        return tab[k];
    }
    else  //error
    {
        return 0;
    }
}

unsigned long int digital_num(unsigned int n, unsigned int K)
{
    if(1 == K)
    {
        return n;
    }
    else
    {
        return (n-my_pow_10(K-1)+1)*K+digital_num(my_pow_10(K-1)-1, K-1);
    }
}
int main()
{
    int n, T;

    cin>>T;
    for(int i=0;i<T;i++)
    {
        cin>>n;
        unsigned int K = (unsigned int)(log(n));
        cout<<digital_num(n, K)<<endl;

    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值