数位dp-剑指 Offer 43. 1~n整数中1出现的次数

465 阅读1分钟

主要思路

  • 数字n转换为string,便于单独处理每一位,s[i]代表当前处理的数字
  • 公式:x位数以内 1的个数,为 x10x1x*10 ^ {x-1}
  • 从个位数s[0]开始处理,将每一位对应的结果存入dp[i]
  • 以n = 2134为例
    • 假如当前s[i] = 3,则dp[3] = 0~34所含的1数目 = OnesIn(0~34)
    1. s[i] == 1时,例子中的i = 1,要处理0~134,dp[i]=OnesIn(099)+OnesIn(034)+OnesIn(百位)dp[i] = One sIn (0~99) + One sIn (0~34) + One sIn(百位) 其中ones in (百位)=ones in (100) + ones in (101~134)
    2. s[i] != 1时,假设i=0,s[i] = 2dp[i]=s[i]OnesIn(0999)+OnesIn(千位)+OnesIn(dp[i+1])dp[i] = s[i] * One sIn (0~999) + One sIn (千位) + One sIn (dp[i+1])

代码实现

公式 x10x1x*10 ^ {x-1}中的x = len(s)-i-1

class Solution:
    def countDigitOne(self, n: int) -> int:
        s = []
        s = str(n)
        l = len(s)
        dp = [0 for _ in range(l+1)]
        for i in range(l-1, -1, -1):
            x = l-i-1
            if s[i] == '1': 
                dp[i] = x*pow(10, x-1) + dp[i+1] + n%int(pow(10, x)) + 1 
            else:
                dp[i] = (int(s[i])-int('0'))*(x)*pow(10, x-1) + min(1, int(s[i])-int('0'))*pow(10,x) + dp[i+1]
        return int(dp[0])