lc1012-至少有1位重复的数字

题目描述

  • 给定正整数 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
}
posted @ 2025-08-30 22:23  余越  阅读(5)  评论(0)    收藏  举报