1. 程式人生 > >一道算法題-從1到n整數中1出現的次數

一道算法題-從1到n整數中1出現的次數

參考 操作 包括 amp blank 一位 時間 www 沒有

1. 題目描述

輸入一個整數n,求從1到n這n個整數的十進制表示中1出現的次數。例如輸入12,從1到12這些整數中包含1的數字有1,10,11和12,1一共出現了5次。

2. 題目來源

第一次看到是在《劍指Offer》第2版上,面試題32。leetcode和牛客網上都有這道題。

3. 本文的目的

看了《劍指Offer》上的解法,我覺得不能算好:

  1. 這段解釋描述有些不清晰,而且沒有圖,難以理解。
  2. 從書中給出的實現上來看,顯得有些淩亂。

在這篇博客裏,會給出一個我對這道題的解法,包括完整的解題思路,完整代碼,時間復雜度分析。

4. 解題思路

考慮將n的十進制的每一位單獨拿出討論,每一位的值記為weight。

1)個位

從1到n,每增加1,weight就會加1,當weight加到9時,再加1又會回到0重新開始。那麽weight從0-9的這種周期會出現多少次呢?這取決於n的高位是多少,看圖:

技術分享圖片


以534為例,在從1增長到n的過程中,534的個位從0-9變化了53次,記為round。每一輪變化中,1在個位出現一次,所以一共出現了53次。
再來看weight的值。weight為4,大於0,說明第54輪變化是從0-4,1又出現了1次。我們記1出現的次數為count,所以:

count = round+1 = 53 + 1 = 54


如果此時weight為0(n=530),說明第54輪到0就停止了,那麽:

count = round = 53

2) 十位

對於10位來說,其0-9周期的出現次數與個位的統計方式是相同的,見圖:

技術分享圖片


不同點在於:從1到n,每增加10,十位的weight才會增加1,所以,一輪0-9周期內,1會出現10次。即rount*10。
再來看weight的值。當此時weight為3,大於1,說明第6輪出現了10次1,則:

count = round*10+10 = 5*10+10 = 60


如果此時weight的值等於0(n=504),說明第6輪到0就停止了,所以:

count = round*10+10 = 5*10 = 50


如果此時weight的值等於1(n=514),那麽第6輪中1出現了多少次呢?很明顯,這與個位數的值有關,個位數為k,第6輪中1就出現了k+1次(0-k)。

我們記個位數為former,則:

count = round*10+former +1= 5*10+4 = 55

3) 更高位

更高位的計算方式其實與十位是一致的,不再闡述。

4) 總結

將n的各個位分為兩類:個位與其它位。
對個位來說:

  • 若個位大於0,1出現的次數為round*1+1
  • 若個位等於0,1出現的次數為round*1

對其它位來說,記每一位的權值為base,位值為weight,該位之前的數是former,舉例如圖:

技術分享圖片


則:

  • 若weight為0,則1出現次數為round*base
  • 若weight為1,則1出現次數為round*base+former+1
  • 若weight大於1,則1出現次數為rount*base+base

比如:

  • 534 = (個位1出現次數)+(十位1出現次數)+(百位1出現次數)=(53*1+1)+(5*10+10)+(0*100+100)= 214
  • 530 = (53*1)+(5*10+10)+(0*100+100) = 213
  • 504 = (50*1+1)+(5*10)+(0*100+100) = 201
  • 514 = (51*1+1)+(5*10+4+1)+(0*100+100) = 207
  • 10 = (1*1)+(0*10+0+1) = 2

5. 完整代碼

 1 int NumberOf1Between1AndN_Solution(int n)
 2     {
 3         if(n<1)
 4             return 0;
 5         int count = 0;
 6         int base = 1;
 7         int round = n;
 8         while(round>0)
 9         {
10             int weight = round%10;
11             round/=10;
12             count += round*base;
13             if(weight==1)
14                     count+=(n%base)+1;
15             else if(weight>1)
16                 count+=base;
17             base*=10;
18         }
19     return count;
20     }

6. 時間復雜度分析

由分析思路或者代碼都可以看出,while循環的次數就是n的位數,logn(以10為底),而循環體內執行的操作都是有限次的,所以時間復雜度為O(logn)

參考文獻:http://blog.csdn.net/yi_afly/article/details/52012593

一道算法題-從1到n整數中1出現的次數