其他算法-031-整數中1出現的次數(從1到n整數中1出現的次數)

題目描述

求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?爲此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於後面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數(從1 到 n 中1出現的次數)。

分析

  • 方法一:記錄單個數字所包含1的個數,相加即可。時間複雜度>O(n),空間複雜度爲O(n)。
  • 方法二:歸納:
    • 從 1 至 10,在它們的個位數中,任意的 X 都出現了 1 次。
    • 從 1 至 100,在它們的十位數中,任意的 X 都出現了 10 次。
    • 從 1 至 1000,在它們的百位數中,任意的 X 都出現了 100 次。

依此類推,從 1 至 10i10^{i},在它們的左數第二位(右數第 i位)中,任意的 X 都出現了 10i110^{i-1}次。

  • 總結一下以上的算法,可以看到,當計算右數第 i 位包含的 1 的個數時:

    • 取第 i 位左邊(高位)的數字,乘以 10i110^{i−1},得到基礎值 a。
    • 取第 i 位數字,計算修正值:
      • 如果大於 1,則結果爲 a+ 10i110^{i−1}
      • 如果小於 1,則結果爲 a。
      • 如果等於 1,則取第 i 位右邊(低位)數字,設爲 b,最後結果爲 a+b+1。
  • 時間複雜度O(n的位數),空間複雜度O(n)

舉例說明

接下來以 n=2593,X=5n=2593,X=5 爲例來解釋如何得到數學公式。從 1 至 2593 中,數字 5 總計出現了 813 次,其中有 259 次出現在個位,260 次出現在十位,294 次出現在百位,0 次出現在千位。

現在依次分析這些數據,首先是個位。從 1 至 2590 中,包含了 259 個 10,因此任意的 X 都出現了 259 次。最後剩餘的三個數 2591, 2592 和 2593,因爲它們最大的個位數字 3 < X,因此不會包含任何 5。

然後是十位。從 1 至 2500 中,包含了 25 個 100,因此任意的 X 都出現了 25×10=25025×10=250 次。剩下的數字是從 2501 至 2593,它們最大的十位數字 9 > X,因此會包含全部 10 個 5。最後總計 250 + 10 = 260。

接下來是百位。從 1 至 2000 中,包含了 2 個 1000,因此任意的 X 都出現了 2×100=2002×100=200 次。剩下的數字是從 2001 至 2593,它們最大的百位數字 5 == X,這時情況就略微複雜,它們的百位肯定是包含 5 的,但不會包含全部 100 個。如果把百位是 5 的數字列出來,是從 2500 至 2593,數字的個數與百位和十位數字相關,是 93+1 = 94。最後總計 200 + 94 = 294。

最後是千位。現在已經沒有更高位,因此直接看最大的千位數字 2 < X,所以不會包含任何 5。到此爲止,已經計算出全部數字 5 的出現次數。

代碼

  • 方法一:
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        counter = 0
        for i in range(n+1):
            counter += self.has1Counter(i)
        
        return counter
    
    def has1Counter(self, number):
        counter = 0
        while number:
            if number%10==1:
                counter += 1
            number //= 10
        return counter
  • 方法二:
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        counter = 0
        for i in range(1,len(str(n))+1):
            high = n//(10**i)  # 高位數字
            low = n%(10**(i-1)) # 低位數字
            now = n//10**(i-1)%10 # 當前位
            
            if now<1:
                counter += high * 10**(i-1)
            elif now>1:
                counter += high *10**(i-1) + 10**(i-1)
            else:
                counter += high*10**(i-1) + low + 1
            
        return counter
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章