您的位置:首页 > 其它

数字统计问题

2015-09-24 15:16 169 查看
1.问题描述

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

2.算法设计

给定表示书的总页码的10进制整数n(1≤n≤109)。编程计算数的全部页码中分别用到多少次数字0,1,2,…,9。

3.数据输入

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

4.结果输出

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

5.求解问题的算法描述

{ 在一个n位十进制数的由低到高的第i位上,总是连续出现10^i个0, 10^i个1, ……, 10^i个9, 9之后又是连续的10^i个0, 10^i个1, ……, 10^i个9,这样循环出现。由此可以在第i位上求出每个数字出现的次数,而在第i个数位上,最前面的10^i个0是前导0,应该在统计的时候减掉。}

以上是我百度到的一段算法解析,没看太明白……

以下是我的分析:

我把页码看成是一个字符串,也就是 一个N位数 PageNum = AB…Z(其中0≤ A,B…,Z ≤9 ),比如A=a, B=b, …, C=c(0≤ a,b, … , z ≤9)

0.在A位置上:

number < a : count[number] += 10^(N-1);

number = a : count[number] += bc…z + 1;

number > a: count[number] += 0;

1.在B位置上:

number < b: count[number] += 10^(N-2) * (a+1);

number = b: count[number] += 10^(N-2) * a + (cd…z + 1);

number > b: count[number] += 10^(N-2) * a

2.在C位置上:

number < c: count[number] += 10^(N-3) * (ab+1);

number = c: count[number] += 10^(N-3) * (de…z + 1);

number > c: count[number] += 10^(N-3) * ab;

……

i.在I位置上:

number < i: count[number] += 10^(N-i-1) * (i前面的数字 + 1);

number = i: count[number] += 10^(N-i-1) * (i后面的数字 + 1);

number > i: count[number] += 10^(N-i-1) * i前面的数字;

[b]PS:以上计算的时候并没有讨论0的情况,而是把0006中0出现的次数一起统计了进去,因此在最后需要去掉前导0的计数![/b]

(思考这题的时候我其实是想从低位开始统计的,这样就可以不用考虑前导0 的问题,但是思考到一半还是换到了从高位开始,我想从低位开始找规律应该也是可行的,有空的时候我再从低位开始找规律的分析下)

(这个过程就像是小学时候的做奥数题,找规律一样~ 奥数题的话只要能找到规律算出答案就行了,但是算法呢还需要考虑得算法复杂度等,虽然不知道我写的算法算不算效率高的, 至少没有去一个一个数字遍历~)

6. 算法实现的关键技巧

在算法中要尤其注意每次循环中对最高位的计算,以及最后要减去前导0的个数。

7.实验分析及结论

public static void main(String[] args) {
int page = 0;
Scanner input;
Formatter output;

//读取页码数
try {
input = new Scanner(Paths.get("input.txt"));
if(input.hasNext()){
page = input.nextInt();
}
input.close();
} catch (IOException e) {
e.printStackTrace();
}

//统计数字
int count[] = count(page);

//写入文件
try {
output = new Formatter("output.txt");
for(int num : count)
output.format("%d%n", num);
output.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
}

}

public static int[] count(int page){
//初始化计数数组
int count[] = new int[10];
for(int i = 0; i < 10; i++){
count[i] = 0;
}

//得出页码数的位/长度
String str = Integer.toString(page);
int len = str.length();

int pre = 0;//前面最高位前面的数字
int now = 0;//当前的最高位
int rem = 0;//当前最高位后面的数字

for(int i = 0; i < len; i++){
rem = page % (int)(Math.pow(10.0, len-i-1));
now = page / (int)(Math.pow(10.0, len-i-1));
//计算小于当前最高位的数字在这个位置出现的次数
for(int j = 0; j < now; j++)
count[j] += Math.pow(10.0, len-i-1) * (pre + 1);
//计算当前最高位的数字在这个位置出现的次数
count[now] += Math.pow(10.0, len-i-1) * pre + rem + 1;
//计算大于当前最高位的数字在这个位置出现的次数
for(int j = now + 1; j <= 9; j++)
count[j] += Math.pow(10.0, len-i-1) * pre;

//将当前最高位加到前面的数字中
pre = pre * 10 + now;
//去掉当前最高位得到的数,也就是前面的余数
page = rem;

}

//去掉对前导0的计数
for(int i = 0; i < len; i++){
count[0] -= Math.pow(10.0, len-i-1);
}

return count;
}


以上就是我的第一题算法题~

希望自己可以坚持下去 :)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: