统计数字问题
统计数字问题,见李晓东《计算机算法设计与分析》1-1。
题意为。给定一个数N求从1到N的这N个数中0,1,2,3,4,5,6,7,8,9这10个数字出现的次数:
同时所有的数字没有前导的0。 如6要写成6而不是 006 ,06这种形式。
举例子: 数字 1011 代表1出现3次 0出现1次。。
《编程之美》上也有求1的个数。不过1比较特殊。李的题是求所有的数字出现的次数
分析如下:
这个分析同《编程之美》但是要扩展下:
我们分别统计在每一个位上数字出现的次数:
假如这个数是 1245
1.我们首先统计 1在 十位上出现的次数 = (12+1)*10 这个很容易能够得出来(分别是 120* 110* 100* .... 000*)注意这里我们算的时候将前导0算在0的记数中,算法最后会去除。
2.如果统计4在十位上出现的次数 = (12)*10 + 5 +1。在这里4就是原来数在十位上的数,此是4并没有通过进位到达5所以它的个数不仅与高位有关也和地位有关。
3。 统计 5在十位上出现的次数 = (12)*10 由于5大于在十位上的数,125*不可能出现在原来的数中,所以这里的个数仅和高位有关系。即(11. 10.09.到00);
通过以上几条规律可以推测得到各位上数字上出现的次数。但是0的个数不准确,因为我们将前导0也算入进来了。那前导0的个数有多少个呢?
如果N是三位数。那么有如下规律:
000
001
....(9)
009
010
....(90)
099
100
....(900)
999
省略 号右面代表个数。
这个规律很明显,前导0的个数和N的位数有关系。。计算很简单就可以实现。
综合以上规律得到代码如下:
void count_num(int a)
{
int count[10] = {0};
int n = 1;
int zero = 0;
int weishu = 0;
while(a/n)
{
weishu++;
int lowp = a - (a/n)*n;
int curr = (a/(n))%10;
int highp = a/(n*10);
for (int i = 0;i<10;i++)
{
if (i<curr)
{
count[i] += (highp+1)*n;
}
else if (i == curr)
{
count[i] += (highp)*n;
count[i] += (lowp+1);
}
else
{
count[i] += (highp)*n;
}
}
n = n*10;
}
int t = 1;
while(t<=weishu)
{
n = n/10 ;
zero += t*(n-1 -n/10 +1);
t++;
}
count[0] = count[0] -zero;
for (int i = 0;i <10;i++)
{
cout<<i<<" "<<count[i]<<endl;
}
}
{
int count[10] = {0};
int n = 1;
int zero = 0;
int weishu = 0;
while(a/n)
{
weishu++;
int lowp = a - (a/n)*n;
int curr = (a/(n))%10;
int highp = a/(n*10);
for (int i = 0;i<10;i++)
{
if (i<curr)
{
count[i] += (highp+1)*n;
}
else if (i == curr)
{
count[i] += (highp)*n;
count[i] += (lowp+1);
}
else
{
count[i] += (highp)*n;
}
}
n = n*10;
}
int t = 1;
while(t<=weishu)
{
n = n/10 ;
zero += t*(n-1 -n/10 +1);
t++;
}
count[0] = count[0] -zero;
for (int i = 0;i <10;i++)
{
cout<<i<<" "<<count[i]<<endl;
}
}