题目描述
- 给定正整数 n,返回在
[1, n] 范围内具有 至少 1 位 重复数字的正整数的个数。
示例
输入:n = 20
输出:1
解释:这个数是 11
输入:n = 100
输出:10
输入:n = 1000
输出:262
题解
- 思路
- 数位DP
- 反过来想,求没有重复位数的数字,用总数减一下就是题目答案
- 主要就是找规律
- 如果是 5 位数,那么 4位数 < 5位数,这里可以减一波(4个):9 * C(9, x), x ∈ [0, 3]
- 第一个数只能是 1-9,若其是 s,则 (s-1) 开头的数 < s 开头的数,又可以减一波
- 后面的数同理,只不过可以为 0
- 需要注意重复的数,所以开一个状态表记录一下
func numDupDigitsAtMostN(n int) int {
res := n
nums := []int{}
for n > 0 {
nums = append(nums, n % 10)
n /= 10
}
size := len(nums)
for i := 1; i < size; i ++ { res -= 9 * C(9, i - 1) }
res -= (nums[size - 1] - 1) * C(9, size - 1)
st := [10]bool{}
st[nums[size - 1]] = true
for i := size - 2; i >= 0; i -- {
x := nums[i]
for j := 0; j < x; j ++ {
if !st[j] {
res -= C(10 - (size - i), i)
}
}
if st[x] { return res }
st[x] = true
}
return res - 1
}
func C(n, m int) int {
res := 1
for i, j := n, 0; j < m; i, j = i - 1, j + 1 {
res *= i
}
return res
}