25.在从1到n的正数中1出现的次数[NumberOf1Between1_N]
【题目】
输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。例如输入12,从1到12这些整数中包含1 的数字有1,10,11和12,1一共出现了5次。
【分析】
这是一道广为流传的google面试题。
普通n*lg(n)的解法。
【解法1】
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
///////////////////////////////////////////////////////////////////////////// // Find the number of 1 in an integer with radix 10 // Input: n - an integer // Output: the number of 1 in n with radix ///////////////////////////////////////////////////////////////////////////// int NumberOf1(unsigned int n) { int number = 0; while(n) { if(n % 10 == 1) number ++; n = n / 10; } return number; } ///////////////////////////////////////////////////////////////////////////// // Find the number of 1 in the integers between 1 and n // Input: n - an integer // Output: the number of 1 in the integers between 1 and n ///////////////////////////////////////////////////////////////////////////// int NumberOf1BeforeBetween1AndN_Solution1(unsigned int n) { // T(n) = n*lg(n) int number = 0; // Find the number of 1 in each integer between 1 and n for(unsigned int i = 1; i <= n; ++ i) number += NumberOf1(i); return number; } |
【解法2】
更加巧妙的lg(n)的解法。
简单的方法就是按照给位进行分析:
在个位出现1的个数=n/10+(个位=0,0;个位>1,1;个位=1,低0位+1);
十位位出现1的个数=n/100*10+(十位=0,0;十位>1,10;十位=1,低一位+1);
百位出现1的个数=n/1000*100+(百位=0,0;百位>1,100;百位=1,低两位+1);
等等。
算法的复杂度仅仅和位数有关。
设第i位出现1的个数为s(i),N为输入整数n的位数。则总和sum= s(1)+…s(i)+…s(N)即为所求。
设bi为整数n的第i位数字,第i位之后的剩余数字为ri;
s(i) = A + B
A = n/10i*10i-1
bi=( n/10i-1)%10
ri= n/10i-1
b(i)==0 ,则B=0
b(i)==1 ,则B=ri+1
b(i)>1 ,则B=10i-1
C++ Code
1
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 |
int PowerBase10(unsigned int n) { // 10^n int result = 1; for(unsigned int i = 0; i < n; ++ i) result *= 10; return result; } int b10(unsigned int n) { return PowerBase10(n); } int NumberBitCount(unsigned int n) { int N = 0; while(n) { n = n / 10; N++; } return N; } int NumberOf1BeforeBetween1AndN_Solution2(unsigned int n) { // T(n) = o(N) = o(lgn) int N = NumberBitCount(n); int si, sum = 0; int A, B, bi, ri; for (int i = 1; i <= N; i++) { A = n / b10(i) * b10(i - 1); bi = n / b10(i - 1) % 10; ri = n % b10(i - 1); if (bi == 0) { B = 0; } else if (bi == 1) { B = ri + 1; } else if (bi > 1) { B = b10(i - 1); } si = A + B; sum += si; } return sum; } |
【参考】
http://zhedahht.blog.163.com/blog/static/25411174200732494452636/
http://www.cnblogs.com/GoAhead/archive/2012/05/28/2521415.html