您的位置:首页 > 其它

统计数字问题

2009-11-23 22:42 260 查看
问题描述如下:
一本书的页码从自然数1开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如第6页用6表示而不是06或006。数字统计问题要求对给定书的总页码,计算出书的全部页码中分别用到多少次数字0,1,2,3,.....9。

《算法设计与分析习题》分析:

考察由0,1,2...9组成的所有n位数。从n个0到n个9共有10^n个n位数。在这10^n个n位数中,0,1,2.....9第个数字使用次数相同,设为f(n)。f(n)满足如下递推式:
n>1: f(n) = 10f(n-1)+10^(n-1)
n = 1: f(n) =1
由此可知,f(n) = n*10^(n-1)。
据此,可从高位向低位进行统计,再减去多余的0的个数即可。

【注:代码中的文字例子描述引用自http://blog.csdn.net/jcwKyl/archive/2008/10/02/3009244.aspx

// 比如,对于一个数字34567,我们可以这样来计算从1到34567之间所有数字中每个数字出现的次数:
// 从0到9999,这个区间的每个数字的出现次数可以使用原著中给出的递推公式,即每个数字出现4000次。
// 从10000到19999,中间除去万位的1不算,又是一个从0000到9999的排列,这样的话,从0到34567之间
// 的这样的区间共有3个。所以从00000到29999之间除万位外每个数字出现次数为3*4000次。然后再统计
// 万位数字,每个区间长度为10000,所以0,1,2在万位上各出现10000次。而3则出现4567+1=4568次。
// 之后,抛掉万位数字,对于4567,再使用上面的方法计算,一直计算到个位即可。
void countNumFast(int num[],int number)
{
int pow10[10]={1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};
int i=-1;
bool flag=true;
int _m=0;//number位数
int n=number;
for (int k=9;k>=1;k--)//个位数另处理
{
if (n/pow10[k]!=0)
{
i=k+1;//n此时是i位数字
if (flag)//记录传入的数的位数,做标记使得后续不能修改
{
_m=i; flag=false;
}
int hi=n/pow10[i-1];//最高位数
//1.记录低于最高位的数字次数
for (int j=0;j<=9;j++)//低于最高位的所有数,有n*10^(n-1)个,一共(hi-0)次
num[j]+=(hi-0)*(i-1)*pow10[i-2];
//2.记录最高位上小于hi的次数
for (int j=0;j<=hi-1;j++)//从0到hi-1每个数字出现10^(i-1)次
num[j]+=pow10[i-1];
//3.记录最高位hi的次数
num[hi]+=n%(pow10[i-1])+1;//最高位hi的次数,等于n%10^(n-1)次+1,加1是为了把低位的0也计算
n=n%pow10[i-1];//去掉高位
}
}

for (int j=0;j<=n;j++)
num[j]+=1;
for (int j=_m-1;j>=0;j--)//去掉多余0
{
num[0]-=pow10[j];
}
}


计算还挺烦的。。呼,幸好有文字描述的例子才慢慢推出来。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: