题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。
例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。
编程之美上的原题。
基本思路1:
每次判断各位是否为1,计数。然后依次/=10即可。
时间复杂度O(N*lgN)
#include <stdio.h> int countone(int num) { int cnt = 0; while(num) { if(num%10==1) { cnt++; } num/=10; } return cnt; } int countone_all(int n) { int sum = 0; int i; for(i=1;i<=n;i++) { sum += countone(i); } return sum; } int main() { int n = 12; printf("%d\n", countone_all(n)); return 0; }
思路2:
可以用归纳法搞出一个递推公式。
但是如书上所述,这个递推公式是有范围限制的,n最大为1111111110。
归纳如下:
如果N为0~9 ,当N>=1时,f(N)=1,否则f(N)=0。
如果N为两位数,f(N)不仅和各位有关,还和十位有关:
(1)如果个位数大于等于1,则个位出现1的次数为十位数的数字加一(加个位的一个1)。如果N的个位数为0,个位出现1的次数就是0。
(2)如果十位数字等于1,则十位上出现1的次数为个位数字加1,如果十位数大于1,则十位数上出现1的次数为10。
可写出程序如下:
long long countone_plus(long long n) { long long iCount = 0; long long iFactor = 1; long long iLowerNum = 0; long long iCurrNum = 0; long long iHigherNum = 0; while( n/iFactor ) { iLowerNum = n - (n / iFactor) * iFactor; iCurrNum = (n/iFactor) % 10; iHigherNum = n / (iFactor * 10); switch(iCurrNum) { case 0: iCount += iHigherNum * iFactor; break; case 1: iCount += iHigherNum * iFactor + iLowerNum + 1; break; default: iCount += (iHigherNum + 1) * iFactor; break; } iFactor *= 10; } return iCount; }