LeetCode 题解工作台

统计强大整数的数目

给你三个整数 start , finish 和 limit 。同时给你一个下标从 0 开始的字符串 s ,表示一个 正 整数。 如果一个 正 整数 x 末尾部分是 s (换句话说, s 是 x 的 后缀 ),且 x 中的每个数位至多是 limit ,那么我们称 x 是 强大的 。 请你返回区间 [s…

category

3

题型

code_blocks

7

代码语言

hub

3

相关题

当前训练重点

困难 · 状态·转移·动态规划

bolt

答案摘要

这道题实际上是求在给定区间 中,满足条件的数的个数。个数与数的位数以及每一位上的数字有关。我们可以用数位 DP 的思路来解决这道题。数位 DP 中,数的大小对复杂度的影响很小。 对于区间 问题,我们一般会将其转化为 然后再减去 $[1,..l - 1]$ 的问题,即:

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你三个整数 start ,finish 和 limit 。同时给你一个下标从 0 开始的字符串 s ,表示一个  整数。

如果一个  整数 x 末尾部分是 s (换句话说,s 是 x 的 后缀),且 x 中的每个数位至多是 limit ,那么我们称 x 是 强大的 。

请你返回区间 [start..finish] 内强大整数的 总数目 。

如果一个字符串 x 是 y 中某个下标开始(包括 0 ),到下标为 y.length - 1 结束的子字符串,那么我们称 x 是 y 的一个后缀。比方说,25 是 5125 的一个后缀,但不是 512 的后缀。

 

示例 1:

输入:start = 1, finish = 6000, limit = 4, s = "124"
输出:5
解释:区间 [1..6000] 内的强大数字为 124 ,1124 ,2124 ,3124 和 4124 。这些整数的各个数位都 <= 4 且 "124" 是它们的后缀。注意 5124 不是强大整数,因为第一个数位 5 大于 4 。
这个区间内总共只有这 5 个强大整数。

示例 2:

输入:start = 15, finish = 215, limit = 6, s = "10"
输出:2
解释:区间 [15..215] 内的强大整数为 110 和 210 。这些整数的各个数位都 <= 6 且 "10" 是它们的后缀。
这个区间总共只有这 2 个强大整数。

示例 3:

输入:start = 1000, finish = 2000, limit = 4, s = "3000"
输出:0
解释:区间 [1000..2000] 内的整数都小于 3000 ,所以 "3000" 不可能是这个区间内任何整数的后缀。

 

提示:

  • 1 <= start <= finish <= 1015
  • 1 <= limit <= 9
  • 1 <= s.length <= floor(log10(finish)) + 1
  • s 数位中每个数字都小于等于 limit 。
  • s 不包含任何前导 0 。
lightbulb

解题思路

方法一:数位 DP

这道题实际上是求在给定区间 [l,..r][l,..r] 中,满足条件的数的个数。个数与数的位数以及每一位上的数字有关。我们可以用数位 DP 的思路来解决这道题。数位 DP 中,数的大小对复杂度的影响很小。

对于区间 [l,..r][l,..r] 问题,我们一般会将其转化为 [1,..r][1,..r] 然后再减去 [1,..l1][1,..l - 1] 的问题,即:

ans=i=1ransii=1l1ansians = \sum_{i=1}^{r} ans_i - \sum_{i=1}^{l-1} ans_i

对于本题而言,我们求出 [1,finish][1, \textit{finish}] 中满足条件的数的个数,然后减去 [1,start1][1, \textit{start} - 1] 中满足条件的数的个数,即可得到答案。

这里我们用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。

基本步骤如下:

  1. 先将 start\textit{start}finish\textit{finish} 转化为字符串,方便后续的数位 DP。
  2. 设计一个函数 dfs(pos,lim)\textit{dfs}(\textit{pos}, \textit{lim}),表示从第 pos\textit{pos} 位开始搜索,当前的限制条件为 lim\textit{lim}
  3. 如果最大的数字位数小于 s\textit{s} 的长度,返回 0。
  4. 如果当前剩余的数字位数等于 s\textit{s} 的长度,判断当前的数字是否满足条件,返回 1 或 0。
  5. 否则,我们计算当前位的上限 up=min(lim?t[pos]:9,limit)\textit{up} = \min(\textit{lim} ? \textit{t}[\textit{pos}] : 9, \textit{limit})。然后遍历当前位的数字 ii,从 0 到 up\textit{up},递归调用 dfs(pos+1,lim&&i==t[pos])\textit{dfs}(\textit{pos} + 1, \textit{lim} \&\& i == \textit{t}[\textit{pos}]),将结果累加到答案中。
  6. 如果当前的 lim\textit{lim} 为 false,则将当前的答案存入缓存中,避免重复计算。
  7. 最后返回答案。

答案为区间 [1,finish][1, \textit{finish}] 中满足条件的数的个数减去区间 [1,start1][1, \textit{start} - 1] 中满足条件的数的个数。

时间复杂度 O(logM×D)O(\log M \times D),空间复杂度 O(logM)O(\log M),其中 MM 为数字的上限,而 D=10D = 10

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Solution:
    def numberOfPowerfulInt(self, start: int, finish: int, limit: int, s: str) -> int:
        @cache
        def dfs(pos: int, lim: int) -> int:
            if len(t) < n:
                return 0
            if len(t) - pos == n:
                return int(s <= t[pos:]) if lim else 1
            up = min(int(t[pos]) if lim else 9, limit)
            ans = 0
            for i in range(up + 1):
                ans += dfs(pos + 1, lim and i == int(t[pos]))
            return ans

        n = len(s)
        t = str(start - 1)
        a = dfs(0, True)
        dfs.cache_clear()
        t = str(finish)
        b = dfs(0, True)
        return b - a
speed

复杂度分析

指标
时间O(\log(\textit{finish}))
空间O(\log(\textit{finish}))
psychology

面试官常问的追问

外企场景
  • question_mark

    Check if the candidate can recognize the need for digit DP in problems involving number ranges and suffixes.

  • question_mark

    Assess whether the candidate can handle edge cases and constraints efficiently, especially when dealing with large inputs.

  • question_mark

    Look for understanding of how dynamic programming can be adapted to count numbers with specific suffixes.

warning

常见陷阱

外企场景
  • error

    Misunderstanding the constraint on digits may lead to incorrect solutions that count numbers outside the valid range.

  • error

    Forgetting to account for all possible numbers with the given suffix in the range could result in an incomplete solution.

  • error

    Failing to optimize for large inputs, leading to time or space inefficiency when handling upper bounds of the range.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Change the limit on the digits to create a different set of valid numbers.

  • arrow_right_alt

    Modify the suffix string to test if the solution can handle varying patterns and lengths.

  • arrow_right_alt

    Increase the range size to test the scalability of the solution with larger upper bounds.

help

常见问题

外企场景

统计强大整数的数目题解:状态·转移·动态规划 | LeetCode #2999 困难