文章内就不再贴题目了,有需要大家可以直接去OJ上查看—统计字数问题。
1. 算法描述
本题目采用了排列组合的思想。分别计算每个数字在每一位上出现的次数,累加之后,即为最后的结果。
需要特别注意的是,我们直接用排列组合直接计算,但是并没有把0 和其他数字分开来算,
所以这样计算出来的结果就是把前导0 也一起算进去了,所以输出结果前应该减掉所有前导0。
文字说明不够直观,下面我举个栗子来帮助大家理解这个算法
栗子
page:25634
| 位次 | 该位上数字 | 0-9 共同出现的次数 | 小于该位上数字的数额外加的值 | 等于该位上的数字的数额外加的值 |
| 个位 | 4 | 2563 * 1 | +1 | +1 |
| 十位 | 3 | 256 * 10 | +10 | +4 |
| 百位 | 6 | 25 * 100 | +100 | +34 |
| 千位 | 5 | 2 * 1000 | +1000 | +634 |
| 万位 | 2 | 0 * 10000 | +10000 | +5634 |
相信大家可以从表格中找到规律,想要动手实现了吧!但是别着急,现在还没有减去前导0 ,减完以后才能得到正确结果.
下面是前导0 出现次数的规律
仍以 25634为例
| 范围 | 前导0个数 |
| 10000+ | 0 |
| 01000 ~ 09999 | 9000 * 1 |
| 00100 ~ 00999 | 900 * 2 |
| 00010 ~ 00099 | 90 * 3 |
| 00001 ~ 00009 | 9 * 4 |
| 00000 | 1 * 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)
本文主要介绍了统计字数问题的算法,通过一个具体的栗子进行说明,页面编号为25634。文章详细阐述了算法描述,提供了代码实现,并对算法的时间复杂度进行了分析,指出其为lg(n)。
432

被折叠的 条评论
为什么被折叠?



