统计字数问题

本文主要介绍了统计字数问题的算法,通过一个具体的栗子进行说明,页面编号为25634。文章详细阐述了算法描述,提供了代码实现,并对算法的时间复杂度进行了分析,指出其为lg(n)。

文章内就不再贴题目了,有需要大家可以直接去OJ上查看—统计字数问题


1. 算法描述

    本题目采用了排列组合的思想。分别计算每个数字在每一位上出现的次数,累加之后,即为最后的结果。
    需要特别注意的是,我们直接用排列组合直接计算,但是并没有把0 和其他数字分开来算,
    所以这样计算出来的结果就是把前导0 也一起算进去了,所以输出结果前应该减掉所有前导0。
    文字说明不够直观,下面我举个栗子来帮助大家理解这个算法

栗子

page:25634

位次该位上数字 0-9 共同出现的次数小于该位上数字的数额外加的值等于该位上的数字的数额外加的值
个位42563 * 1+1+1
十位3256 * 10+10+4
百位625 * 100+100+34
千位52 * 1000+1000+634
万位20 * 10000+10000+5634

相信大家可以从表格中找到规律,想要动手实现了吧!但是别着急,现在还没有减去前导0 ,减完以后才能得到正确结果.
下面是前导0 出现次数的规律
仍以 25634为例
范围前导0个数
10000+0
01000 ~ 099999000 * 1
00100 ~ 00999900 * 2
00010 ~ 0009990 * 3
00001 ~ 000099 * 4
000001 * 5


相信规律并不难找到,就不再啰嗦了。


2. 代码实现

import java.io.IOException;
import java.util.Scanner;

/**
 * Created by chen_swe on 3/12/16.
 */

public class Main {

    /**
     * 计算并累加第[lg(base) - 1] 位(从右向左)各个数字出现的次数
     *
     * @param page 总页数
     * @param base 基数,用来确定当前计算的是哪一位。
     * @param num  整形数组,用来存放各个数字出现的次数。
     */
    public static void handle(final int page, int base, int[] num) {
        int s = page / (base * 10);
        int l = page % (base * 10);
        int special = l / base;
        l %= base;
        for (int i = 0; i < 10; ++i) {
            num[i] += s * base;
            if (i < special)
                num[i] += base;
            if (i == special)
                num[i] += l + 1;
        }
    }

    /**
     * 减去前导0的个数
     *
     * @param page 总页数
     * @param num  整形数组,用来存放各个数字出现的次数。
     */
    public static void DealWithZero(int page, int[] num) {
        int len = String.valueOf(page).length();
        int tmp = 9 * (int) Math.pow(10, len - 2);
        int number = 1;
        while (tmp != 0) {
            num[0] -= tmp * number;
            tmp /= 10;
            ++number;
        }
        num[0] -= len;
    }

    public static void main(String[] args) throws IOException {
        Scanner cin =new Scanner(System.in);
        final int Page = cin.nextInt();

        int[] num = new int[10];

        int base = 1;
        while (true) {
            handle(Page, base, num);
            base *= 10;
            if (Page / base == 0)
                break;
        }
        DealWithZero(Page, num);

        for (int i : num)
            System.out.println(i);
    }
}

3. 算法分析

时间复杂度 lg(n)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值