统计数字问题(Java)

问题描述

    一本书的页码从自然数1开始顺序编码直到自然数n。输的页码按照通常的习惯编排,每个页码都不含有多余的前导数字0。例如,第6页用数字6表示,而不是06或者006等。数字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2…8,9。

算法设计:给定表示书的总页码的十进制整数n(1<=n<=10^9),计算书的全部页码中分别用到多少次数字0,1,2…8,9。

数据输入:输入数据由文件名为input.txt的文本提供。每个文件只有1行,给出表示书的总页码的整数n。

结果输出:将计算结果输出到文件output.txt。输出文件总共10行,在第k行输出页码中用到数字k-1的次数,k=1,2,…,10。

题解

方法1(暴力求解)

    遍历每一个数字的每位数,对应数字出现的次数+1
代码

public static void count_one(File in, File out) throws FileNotFoundException {
        Scanner sc = new Scanner(in);
        int n=sc.nextInt(); //书的总页码
        int[] arr = new int[10];
        int i,j,m;
        for (i=1;i<=n;i++){
            if (i<10){
                arr[i]++;
            }
            if (i>=10){
                j=i;
                while (j!=0){
                    m=j%10; //求余
                    arr[m]++;
                    j=j/10;
                }
            }
        }
        PrintWriter p = new PrintWriter(out);
        for (i=0;i<10;i++){
            p.println(arr[i]);
        }
        p.close();
        sc.close();
    }

方法2(补0+部分暴力求解)

补0

  n位数字,共有10n种可能(0…0也算),那么0-9每一个数字都出现了n*10n-1次。
  0-9 无效的0个数:1
  00-99 无效的0的个数:10+1(00-09)共有11个0无效
  000-999 无效的0的个数:100+10+1
由此,我们可以发现无效的0个数f(n)
f ( n ) = {   1 n = 0   1 0 n − 1 + f ( n − 1 ) n > 0 f(n) = \begin{cases} \ 1 & n = 0 \\ \ 10^{n-1}+f(n-1) &n>0 \end{cases} f(n)={ 1 10n1+f(n1)n=0n>0

分区

  将数字n分为几个区,例如将3825分为[000, 999], [1000, 1999], [2000, 2999]三部分。
先忽略后两个分区的最高位,那相当于三个[000,999],那0-9各出现了 3 * 3 * 10(3-1) 次。
  这三个分区中只有第一个分区才有无效的0,个数为f(length-1)
  长度为length的数字n有这样的分区数p=n/(10length-1)
统计最高位
  最高位分别为1,…, p,各自出现了10length-1
剩余部分[3000, 3825]使用暴力求解的方法,即[p*10(length-1), n]
代码

//补0+部分暴力求解
    public static void count_two(File in, File out) throws FileNotFoundException {
        Scanner sc = new Scanner(in);
        int n = sc.nextInt();
        String s = String.valueOf(n);
        int length = s.length();
        int[] arr = new int[10];

        int p = area_num(n,length);//块数
        for (int i=0;i<10;i++){
            arr[i]+=p*fn(length-1);
        }
        //处理分区最高位
        if (p>1){
            for (int i=1;i<p;i++){
                arr[i]+=power(10,length-1);
            }
        }
        int zero = zero_num(length-1);
        arr[0]-=zero;
        //处理剩余的数
        int r = p*power(10,length-1);
        int i,j,m;
        for (i=r;i<=n;i++){
            if (i<10){
                arr[i]++;
            }
            if (i>=10){
                j=i;
                while (j!=0){
                    m=j%10; //求余
                    arr[m]++;
                    j=j/10;
                }
            }
        }
        PrintWriter pw = new PrintWriter(out);
        for (i=0;i<10;i++){
            pw.println(arr[i]);
        }
        pw.close();
        sc.close();
    }
    //求单块分区0-9出现的次数
    public static int fn(int n){
        return n*power(10,n-1);
    }
    //求分区块数
    public static int area_num(int n,int length){
        return n/(power(10,length-1));
    }
    //求无效0的个数
    public static int zero_num(int length){
        if (length==1){
            return 1;
        }
        int num = power(10,length-1)+zero_num(length-1);
        return num;
    }
    //求a^b
    public static int power(int a, int b) {
        return (int) Math.pow(a, b);
    }

运算速度对比

在这里插入图片描述

总结

  网上还有O(logn)的方法,我没完全看懂,在它基础上加上暴力求解,速度比它慢,但比暴力求解要快。

### 回答1: 这是一个统计数字问题:一本书的页面从自然数1开始顺序编码直到自然数n。书的页码按照通常的习惯排序,每个页面都不含多余的前导数字0。例如第6页表示为6而不是06,所以数字统计问题对给定书的总页面数,计算出书中含有多少个前导数字0。例如第6页表示为6而不是06,因此需要计算给定书的总页码数,计算出页面中含有多少个前导数字0,然后将结果给出。 ### 回答2: 数字1到9分别出现了多少次? 首先,我们可以将页码分为两类:一位数页码和多位数页码。对于一位数页码,数字1到9都会出现一次,因此它们的出现总次数为9。对于多位数页码,我们可以将其拆分为高位部分和低位部分。例如,当页码为123时,高位部分为12,低位部分为3。 接下来,我们分别计算高位部分和低位部分中数字1到9的出现次数。 对于高位部分,我们可以通过枚举它的范围来计算。假设总页码数为n,当高位部分的范围为1到n时,数字1到9都会出现 n/10 次。当高位部分的范围为10到n时,数字1到9都会出现 (n/100)*10 + min(max(n mod 100 - 9, 0), 10) 次。其中,(n/100)*10 表示百位数字1到9在所有100页中每个位置都出现了10次,max(n mod 100 - 9, 0) 表示余数部分的最大值减去9,即去掉余数部分中1到9的个数,min(...) 表示去掉1到9之后,余数部分中最多只能再出现10个数字。例如,当n=123时,高位部分的范围为1到12,1到9每个数字都出现了12次,10到12每个数字都出现了3次(因为余数部分只有三个数字),因此高位部分中数字1到9的出现次数为12*9 + 3*3 = 111。 对于低位部分,我们可以分别计算出每个数字在个位、十位、百位等位置上出现的总次数,然后将它们加起来。例如,当低位部分为3时,它在个位上出现了 n/10 次,即页码以3结尾的页数总数;它在十位上出现了n/100次,即页码以13、23、33、...、n-7、n-6、n-5、n-4、n-3、n-2、n-1结尾的页数总数;它在百位及以上位置上都不出现。分别计算数字1到9的低位部分出现次数,并将它们加起来,即可得到它们的总出现次数。 综上所述,我们可以通过上述方法计算出数字1到9在所有页码中的出现次数。 ### 回答3: 数字1在书的页码中一共出现了多少次。 这是一道有趣的数学题,需要我们先用逻辑思维找到规律,再用数学方法进行解。 我们先来看一下如何计算数字1在个位数上出现的次数。 在1~9这9个数字中,数字1只出现了1次,即数字1。在10~19这10个数字中,数字1出现了1次,即数字11。在20~29这10个数字中,数字1又出现了1次,即数字21。以此类推,我们可以发现,在个位数上,数字1的出现次数是固定的,每10个数字中出现1次。 同样的,我们来看一下十位数上数字1的出现次数。在1~99这个范围内,数字1出现了10次,分别是10、11、12、13、14、15、16、17、18和19。而在100~199这个范围内,数字1出现了20次,分别是110~119以及所有的11x(如111、112等)。可见,在十位数上,数字1的出现次数也是固定的,每100个数字中出现10次。 通过上述的分析,我们可以总结出规律:对于一个整数n,我们可以分别计算它的个位数、十位数、百位数……上数字1的出现次数,然后将结果累加即可。其中,对于每个位数上数字1的出现次数,可以使用以下公式进行计算: 对于个位数上数字1的出现次数: (n÷10)×1 + min(max(n mod 10 – 1, 0), 1) 对于十位数上数字1的出现次数: (n÷100)×10 + min(max(n mod 100 – 10 + 1, 0), 10) 对于百位数上数字1的出现次数: (n÷1000)×100 + min(max(n mod 1000 – 100 + 1, 0), 100) 以此类推。其中,min和max函数用于确保计算结果的正确性。具体实现时,可以使用代码来计算出某个整数上数字1的出现次数,然后将这些结果累加即可。 最后,总结一下本题的解题思路: 1. 分别计算给定整数n的个位数、十位数、百位数……上数字1的出现次数。 2. 将上述结果累加,得到整数n上数字1的总出现次数。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值