统计数字问题

统计数字问题,见李晓东《计算机算法设计与分析》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;
    }
    
}

 

 

 

posted @ 2010-09-01 21:55  David Luo  阅读(1224)  评论(2编辑  收藏  举报