一、问题描述:
统计数字问题:一本书的页码从自然数1开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如,第6页用数字6表示,而不是06或006等。数字计数问题要求对给定书的总页码n,计算出书的全部页码中分别用到多少次数字0,1,2,…,9.
二、算法描述:
解法一:直接一位一位的取,一个一个的求。
start
输入页码数n值
定义整数count决定循环的进程
定义整数数组a,长度为10用来统计出现的0,1,2,,,9次数
//刚好可以利用下标进行统计
for(count=1 ; count<=n ; count++){
定义整数s,用于接收count的值
for( ; s!=0 ; s=s/10){
定义整数flag,用于接收每一次从s中分离出来的数字
flag = s ;
a[flag]++;
}
}
//建立一个循环用于输出结果
定义整数 i,用于对流程的控制
for(i=0 ; i<=9 ; i++){
输出:数字 i 出现的次数为a[i]
}
End
解法二:
利用这个规律——由0,1,2,····9组成的所有n位数。从n个0到n个9一共有10n个n为数。在这10n个n位数中,0,1,2,····9每个数字使用的次数相同,设为f(n)。f(n)=n10n-1。后面再去掉多算的零。
Start
输入页码数n值
利用count函数计算未处理之前的0~9出现的个数情况并存在num数组中
利用delete函数计算多计算0出现的个数
输出最后的结果
输入
End
整数 Delete(输入总页码数n的位数){
定义整数变量sum用于累加
for(int i = n的位数;i大于等于1;i减一){
sum+=(int)Math.pow(10,i-1);
}
return sum;
}
void count(输入总页码数n的值){
//分组批次处理
for(int i = 0;i<10;i++) {
num[i] += n的首位*n的长度减一*10的n的长度减二的次方
}
//首位的处理
for(int i=0;i<n的首位;i加一){
num[i]+= 10的n的长度减1的次方
}
//余数最高位出现的次数+整数的情形
num[n的首位]+=n的余数加一
//对余数进行处理
//情况一:余数为零
if(n的余数为零){
num[0]+=n的长度减一
return
}
//情况二:余数不为零,但是余数和最高位之间夹着零
if(n的长度减一!=余数的长度){
num[0]+=(余数-1-余数的长度)*(余数加一)
}
//情况三:正常情况
count(n的余数)
}
三、代码求解:
解法一:直接一位一位的取,一个一个的求。
import java.util.*;
public class MyCount {
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] a = new int[10];
int count;//用于遍历循环
int s;//用于接收count的值
for(count=1;count<=n;count++) {
s=count;
for (int flag;s!=0;s=s/10) {
flag = s;
a[flag]++;//计数
}
}
//建立一个循环用于输出结果
for (int i=0;i<10;i++) {
System.out.println("数字"+i+"出现的次数为"+a[i]);
}
}
}
解法二:
利用这个规律——由0,1,2,····9组成的所有n位数。从n个0到n个9一共有10n个n为数。在这10n个n位数中,0,1,2,····9每个数字使用的次数相同,设为f(n)。f(n)=n10n-1。后面再去掉多算的零。
import java.util.*;
public class MyCount {
public static int num[] = new int[10];
public static void main(String args[]) {
//接收输入
Scanner sc = new Scanner(System.in);
//转换为数字接收
int n = 0;
n = sc.nextInt();
//利用Count函数计算未处理之前的计数
count(n);
//减去多算的0的个数
num[0] -= delete(getLength(n));
//打印结果
for(int i = 0;i<10;i++) {
System.out.println(num[i]);
}
}
//删除多余的数字个数
public static int delete(int length) {
int sum = 0;
//这里利用的是多加0的增长规律,譬如1~10,多算了10个0,1~100多算了100个0
for(int i = length;i>=1;i--) {
sum+=(int)Math.pow(10, i-1);
}
return sum;
}
//获得数字的长度
public static int getLength(int num) {
return (int)Math.log10(num)+1;
}
//获得数字的首位
public static int getHead(int num) {
return num/(int)Math.pow(10, getLength(num)-1);
}
//获得数字除去最高位后的余数
public static int getRemainder(int num) {
return num%(int)Math.pow(10, getLength(num)-1);
}
//计算数字的总数
public static void count(int n) {
//分组处理,这个规律是推出来的
for(int i = 0;i<10;i++) {
num[i] = num[i]+getHead(n)*(getLength(n)-1)*(int)Math.pow(10, getLength(n)-2);
}
//首位的处理
for(int i = 0;i<getHead(n);i++) {
num[i] += (int)Math.pow(10, getLength(n)-1);
}
//余数最高位出现的次数+整数情形
num[getHead(n)]+=getRemainder(n)+1;
//判断余数的情况
//情况一:余数为零,加最大的整数的后长度减一个的0
if(getRemainder(n)==0) {
num[0]+=getLength(n)-1;
return;
}
//情况二:余数不为零,但是余数和最高位之间夹着零,夹了几个*余数的个数
if(getLength(n)-1!=getLength(getRemainder(n))) {
num[0]+=(getRemainder(n)-1-getLength(getRemainder(n)))*(getRemainder(n)+1);
}
//情况三:正常情况,递归进行
count(getRemainder(n));
}
}
Ending... ...