跳至主要內容

面试题 17.06. 2出现的次数

ITCharge大约 3 分钟

面试题 17.06. 2出现的次数open in new window

  • 标签:递归、数学、动态规划
  • 难度:困难

题目链接

题目大意

描述:给定一个整数 nn

要求:计算从 00nn (包含 nn) 中数字 22 出现的次数。

说明

  • n109n \le 10^9

示例

  • 示例 1:
输入: 25
输出: 9
解释: (2, 12, 20, 21, 22, 23, 24, 25)(注意 22 应该算作两次)

解题思路

思路 1:动态规划 + 数位 DP

nn 转换为字符串 ss,定义递归函数 def dfs(pos, cnt, isLimit): 表示构造第 pospos 位及之后所有数位中数字 22 出现的个数。接下来按照如下步骤进行递归。

  1. dfs(0, 0, True) 开始递归。 dfs(0, 0, True) 表示:
    1. 从位置 00 开始构造。
    2. 初始数字 22 出现的个数为 00
    3. 开始时受到数字 nn 对应最高位数位的约束。
  2. 如果遇到 pos==len(s)pos == len(s),表示到达数位末尾,此时:返回数字 22 出现的个数 cntcnt
  3. 如果 poslen(s)pos \ne len(s),则定义方案数 ansans,令其等于 00,即:ans = 0
  4. 如果遇到 isNum==FalseisNum == False,说明之前位数没有填写数字,当前位可以跳过,这种情况下方案数等于 pos+1pos + 1 位置上没有受到 pospos 位的约束,并且之前没有填写数字时的方案数,即:ans = dfs(i + 1, state, False, False)
  5. 如果 isNum==TrueisNum == True,则当前位必须填写一个数字。此时:
    1. 因为不需要考虑前导 00 所以当前位数位所能选择的最小数字(minXminX)为 00
    2. 根据 isLimitisLimit 来决定填当前位数位所能选择的最大数字(maxXmaxX)。
    3. 然后根据 [minX,maxX][minX, maxX] 来枚举能够填入的数字 dd
    4. 方案数累加上当前位选择 dd 之后的方案数,即:ans += dfs(pos + 1, cnt + (d == 2), isLimit and d == maxX)
      1. cnt + (d == 2) 表示之前数字 22 出现的个数加上当前位为数字 22 的个数。
      2. isLimit and d == maxX 表示 pos+1pos + 1 位受到之前位 pospos 位限制。
  6. 最后的方案数为 dfs(0, 0, True),将其返回即可。

思路 1:代码

class Solution:
    def numberOf2sInRange(self, n: int) -> int:
        # 将 n 转换为字符串 s
        s = str(n)
        
        @cache
        # pos: 第 pos 个数位
        # cnt: 之前数字 2 出现的个数。
        # isLimit: 表示是否受到选择限制。如果为真,则第 pos 位填入数字最多为 s[pos];如果为假,则最大可为 9。
        def dfs(pos, cnt, isLimit):
            if pos == len(s):
                return cnt
            
            ans = 0            
            # 不需要考虑前导 0,则最小可选择数字为 0
            minX = 0
            # 如果受到选择限制,则最大可选择数字为 s[pos],否则最大可选择数字为 9。
            maxX = int(s[pos]) if isLimit else 9
            
            # 枚举可选择的数字
            for d in range(minX, maxX + 1): 
                ans += dfs(pos + 1, cnt + (d == 2), isLimit and d == maxX)
            return ans
    
        return dfs(0, 0, True)

思路 1:复杂度分析

  • 时间复杂度O(logn)O(\log n)
  • 空间复杂度O(logn)O(\log n)