统计数字问题,见李晓东《计算机算法设计与分析》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的位数有关系。。计算很简单就可以实现。
综合以上规律得到代码如下:
{
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;
}
}