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

http://blog.csdn.net/sjf0115/article/details/8600599