LeetCode 题解工作台

统计特殊整数

如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数 。 给你一个 正 整数 n ,请你返回区间 [1, n] 之间特殊整数的数目。 示例 1: 输入: n = 20 输出: 19 解释: 1 到 20 之间所有整数除了 11 以外都是特殊整数。所以总共有 19 个特殊整数。 示例 2:…

category

2

题型

code_blocks

5

代码语言

hub

3

相关题

当前训练重点

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

bolt

答案摘要

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

Interview AiBox logo

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

试试 AiBox 面试助手arrow_forward
description

题目描述

如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数

给你一个  整数 n ,请你返回区间 [1, n] 之间特殊整数的数目。

 

示例 1:

输入:n = 20
输出:19
解释:1 到 20 之间所有整数除了 11 以外都是特殊整数。所以总共有 19 个特殊整数。

示例 2:

输入:n = 5
输出:5
解释:1 到 5 所有整数都是特殊整数。

示例 3:

输入:n = 135
输出:110
解释:从 1 到 135 总共有 110 个整数是特殊整数。
不特殊的部分数字为:22 ,114 和 131 。

 

提示:

  • 1 <= n <= 2 * 109
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,..n][1,..n] 的值即可。

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

我们根据题目信息,设计一个函数 dfs(i,mask,lead,limit)\textit{dfs}(i, \textit{mask}, \textit{lead}, \textit{limit}),其中:

  • 数字 ii 表示当前搜索到的位置,我们从高位开始搜索,即 i=0i = 0 表示最高位。
  • 数字 mask\textit{mask} 表示当前数字的状态,即 mask\textit{mask} 的第 jj 位为 11 表示数字 jj 已经被使用过。
  • 布尔值 lead\textit{lead} 表示当前是否只包含前导 00
  • 布尔值 limit\textit{limit} 表示当前是否受到上界的限制。

函数的执行过程如下:

如果 ii 超过了数字 nn 的长度,说明搜索结束,如果此时 lead\textit{lead} 为真,说明当前数字只包含前导 00,直接返回 00,否则返回 11

如果 limit\textit{limit} 为假且 lead\textit{lead} 为假且 mask\textit{mask} 的状态已经被记忆化,直接返回记忆化的结果。

否则,我们计算当前数字的上界 upup,如果 limit\textit{limit} 为真,upup 为当前数字的第 ii 位,否则 up=9up = 9

然后我们遍历 [0,up][0, up],对于每个数字 jj,如果 mask\textit{mask} 的第 jj 位为 11,说明数字 jj 已经被使用过,直接跳过。否则,如果 lead\textit{lead} 为真且 j=0j = 0,说明当前数字只包含前导 00,递归搜索下一位,否则递归搜索下一位并更新 mask\textit{mask} 的状态。

最后,如果 limit\textit{limit} 为假且 lead\textit{lead} 为假,将当前状态记忆化。

最终返回答案。

时间复杂度 O(m×2D×D)O(m \times 2^D \times D),空间复杂度 O(m×2D)O(m \times 2^D)。其中 mm 为数字 nn 的长度,而 D=10D = 10

相似题目:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
    def countSpecialNumbers(self, n: int) -> int:
        @cache
        def dfs(i: int, mask: int, lead: bool, limit: bool) -> int:
            if i >= len(s):
                return int(lead ^ 1)
            up = int(s[i]) if limit else 9
            ans = 0
            for j in range(up + 1):
                if mask >> j & 1:
                    continue
                if lead and j == 0:
                    ans += dfs(i + 1, mask, True, limit and j == up)
                else:
                    ans += dfs(i + 1, mask | 1 << j, False, limit and j == up)
            return ans

        s = str(n)
        return dfs(0, 0, True, True)
speed

复杂度分析

指标
时间Depends on the final approach
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Evaluate the candidate's understanding of dynamic programming and recursion.

  • question_mark

    Assess if the candidate can handle large input sizes efficiently.

  • question_mark

    Test the candidate's ability to reduce a brute-force approach to a more optimized solution using state transitions.

warning

常见陷阱

外企场景
  • error

    Forgetting to memoize intermediate results, leading to redundant calculations.

  • error

    Incorrectly handling leading zeros or invalid digits.

  • error

    Failing to consider all digit positions, which can result in incorrect counts.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Extend the problem to count special integers within a range [m, n].

  • arrow_right_alt

    Count the number of special integers that can be formed by rearranging the digits of n.

  • arrow_right_alt

    Modify the problem to include additional constraints, such as excluding certain digits.

help

常见问题

外企场景

统计特殊整数题解:状态·转移·动态规划 | LeetCode #2376 困难