关于统计数字问题的算法
一本书的页码从自然数1开始顺序编码直到自然数n。书的页码按照通常的习惯编排,每个页码都不含多余的前导数字0。例如第6页用6表示而不是06或006。数字统计问题要求对给定书的总页码,计算出书的全部页码中分别用到多少次数字0,1,2,3,.....9。 void statNumber(int n) { int i,t; int count[10] = {0}; for(i = 1; i <= n; i++) { t = i; while(t) { count[t%10]++; t/=10; } } for(i = 0; i < 10; i++) { printf("%d/n",count[i]); } } 仔细考虑m个n位十进制数的特点,在一个n位十进制数的由低到高的第i个数位上,总是连续出现10^i个0,然后是10^i个1……一直到10^i个9,9之后又是连续的10^i个0,这样循环出现。找到这个规律,就可以在常数时间内算出第i个数位上每个数字出现的次数。而在第i个数位上,最前面的10^i个0是前导0,应该把它们减掉。 这样,可以只分析给定的输入整数n的每个数位,从面可以得到一个log10(n)的算法,代码如下: void statNumber(int n) { int m,i,j,k,t,x,len = log10(n); char d[16]; int pow10[12] = {1},count[10] = {0}; for(i = 1; i < 12; i++) { pow10[i] = pow10[i-1] * 10; } sprintf(d,"%d",n); m = n+1; for(i = 0; i <= len; i++) { x = d[i] - '0'; t = (m-1) / pow10[len-i]; count[x] += m - t * pow10[len-i]; t /= 10; j = 0; while(j <= x-1) { count[j] += (t + 1) * pow10[len-i]; j++; } while(j < 10) { count[j] += t * pow10[len - i]; j++; } count[0] -= pow10[len-i]; /* 第i个数位上前10^i个0是无意义的 */ } for(j = 0; j < 10; j++) { printf("%d/n",count[j]); } }
通过对随机生成的测试数据的比较,可以验证第二段代码是正确的。 其原因是第一段代码时间复杂度为O(n*log10(n)),对m个输入整数进行计算,则需要的时间为 1*log10(1) + 2*log10(2) + ... + m*log10(m), 当n > 10时,有 上面的代码中有个pow10数组用来记录10^i,但10^10左右就已经超过了2^32,但是题目给定的输入整数的范围在10^9以内,所以没有影响。 void statNumber_iterative(int n) { int len,h,m; int count[10] = {0}; int pow10[12] = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000}; char d[16]; len = log10(n); /* len表示当前数字的位权 */ m = len; sprintf(d,n); k = 0; /* k记录当前最高位数字在d数组中的下标 */ h = d[k] - '0'; /* h表示当前最高位的数字 */ n %= pow10[len]; /* 去掉n的最高位 */ while(len > 0) { if(h == 0) { count[0] += n + 1; h = d[++k] - '0'; --len; n %= pow10[len]; continue; } for(i = 0; i < 10; i++) { count[i] += h * len * pow10[len-1]; } for(i = 0; i < h; i++) { count[i] += pow10[len]; } count[h] += n + 1; --len; h = d[++k] - '0'; n %= pow10[len]; } for(i = 0; i <= h; i++) { count[i] += 1; } /* 减去前导0的个数 */ for(i = 0; i <= m; i++) { count[0] -= pow10[i]; } for(i = 0; i < 10; i++) { printf("%d/n",count[i]); } } 以上就是本文的全部内容,希望对大家的学习有所帮助。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |