LeetCode 题解工作台
至少有 1 位重复的数字
给定正整数 n ,返回在 [1, n] 范围内具有 至少 1 位 重复数字的正整数的个数。 示例 1: 输入: n = 20 输出: 1 解释: 具有至少 1 位重复数字的正数( 示例 2: 输入: n = 100 输出: 10 解释: 具有至少 1 位重复数字的正数( 示例 3: 输入: n = …
2
题型
5
代码语言
3
相关题
当前训练重点
困难 · 状态·转移·动态规划
答案摘要
题目要求统计 中至少有一位重复的数字的个数,我们可以换一种思路,用一个函数 统计 中没有重复数字的个数,那么答案就是 $n - f(n)$。 另外,我们可以用一个二进制数来记录数字中出现过的数字,比如数字中出现了 , , ,那么对应的二进制数就是 。
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 状态·转移·动态规划 题型思路
题目描述
给定正整数 n,返回在 [1, n] 范围内具有 至少 1 位 重复数字的正整数的个数。
示例 1:
输入:n = 20 输出:1 解释:具有至少 1 位重复数字的正数(<= 20)只有 11 。
示例 2:
输入:n = 100 输出:10 解释:具有至少 1 位重复数字的正数(<= 100)有 11,22,33,44,55,66,77,88,99 和 100 。
示例 3:
输入:n = 1000 输出:262
提示:
1 <= n <= 109
解题思路
方法一:状态压缩 + 数位 DP
题目要求统计 中至少有一位重复的数字的个数,我们可以换一种思路,用一个函数 统计 中没有重复数字的个数,那么答案就是 。
另外,我们可以用一个二进制数来记录数字中出现过的数字,比如数字中出现了 , , ,那么对应的二进制数就是 。
接下来,我们用记忆化搜索来实现数位 DP。从起点向下搜索,到最底层得到方案数,一层层向上返回答案并累加,最后从搜索起点得到最终的答案。
基本步骤如下:
我们将数字 转为字符串 ,接下来,我们设计一个函数 ,其中:
- 数字 表示当前处理的数字下标,从 开始。
- 数字 表示当前数字中出现过的数字,用二进制数表示。其中 的二进制的第 位为 表示数字 出现过,为 表示数字 没有出现过。
- 布尔值 表示是否只包含前导零。
- 布尔值 表示当前位置是否受到上界的限制。
函数的执行过程如下:
如果 大于等于 ,说明我们已经处理完了所有的位数,此时如果 为真,说明当前的数字是前导零,我们应当返回 ;否则,我们应当返回 。
否则,我们计算当前位置的上界 ,如果 为真,则 为 对应的数字,否则 为 。
然后,我们在 的范围内枚举当前位置的数字 ,如果 为 且 为真,我们递归计算 ;否则,如果 的第 位为 ,我们递归计算 。累加所有的结果即为答案。
答案为 。
时间复杂度 ,空间复杂度 。其中 。
相似题目:
class Solution:
def numDupDigitsAtMostN(self, n: int) -> int:
@cache
def dfs(i: int, mask: int, lead: bool, limit: bool) -> int:
if i >= len(s):
return lead ^ 1
up = int(s[i]) if limit else 9
ans = 0
for j in range(up + 1):
if lead and j == 0:
ans += dfs(i + 1, mask, True, False)
elif mask >> j & 1 ^ 1:
ans += dfs(i + 1, mask | 1 << j, False, limit and j == up)
return ans
s = str(n)
return n - dfs(0, 0, True, True)
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | Depends on the final approach |
| 空间 | Depends on the final approach |
面试官常问的追问
外企场景- question_mark
They hint at counting numbers with no duplicate digits first instead of constructing repeated-digit numbers directly.
- question_mark
They ask how many valid numbers exist with exactly K digits, pointing you toward permutations and digit-state transitions.
- question_mark
They focus on prefix decisions against n, which is a strong signal for digit DP with a tight bound.
常见陷阱
外企场景- error
Forgetting that leading zeros should not mark digit 0 as used, which corrupts counts for shorter numbers.
- error
Subtracting the wrong baseline by including 0 as a positive integer, which shifts the final answer by one.
- error
Trying to count repeated-digit cases directly and double-counting numbers that repeat more than one digit or repeat in multiple positions.
进阶变体
外企场景- arrow_right_alt
Return the count of numbers in [1, n] with all distinct digits instead of repeated digits.
- arrow_right_alt
Count numbers in an arbitrary range [a, b] by computing the result up to b and subtracting the result up to a - 1.
- arrow_right_alt
Change the rule from any repeated digit to exactly one repeated digit, which requires a richer DP state than a simple used-digit mask.