6151. Count Special Integers

Leetcode:https://leetcode.cn/problems/count-special-integers

We call a positive integer special if all of its digits are distinct.

Given a positive integer n, return the number of special integers that belong to the interval [1, n].

Example 1:

Input: n = 20
Output: 19
Explanation: All the integers from 1 to 20, except 11, are special. Thus, there are 19 special integers.

Example 2:

Input: n = 5
Output: 5
Explanation: All the integers from 1 to 5 are special.

Example 3:

Input: n = 135
Output: 110
Explanation: There are 110 integers from 1 to 135 that are special.
Some of the integers that are not special are: 22, 114, and 131.

Constraints: 1 <= n <= 2 * 1e9


组合数学 + 回溯

不用 unordered_set 直接用数组做哈希表就过了 😠 。

假设 n 的位数是 m ,那么我们先求出:所有小于 m 位的「特殊整数」的数目(即位数 i = 1, ..., m),那么有:

i=1m19A9i1

排列组合的思想,可供使用的数字有 10 个,第一位不能是 0 (从 1-9 任选一个),其后的 i - 1 位,还有 9 个数字可以选择。

现考虑 m 位的「特殊整数」,假设 n 的字符串形式是 str

  • 如果第一位选择 < str[0] 的字符,一共有 str[0] - '0' - 1 种选择,其后的 m - 1 位一共有 A9m1 种选择。
  • 否则,第一位选择 str[0] 的字符,定义递归函数 helper ,回溯计算小于 str[1: ] 的特殊整数的数量。
class Solution
{
  public:
    // 使用 used 未标记的数字,填充每一个 nums[idx] ,并使得 nums <= limit
    void helper(const string &limit, string &nums, int idx, bool used[10], int &cnt)
    {
        int n = nums.length();
        if (idx >= n || nums > limit)
        {
            cnt += (nums <= limit);
            return;
        }
        for (int i = 0; i <= 9; ++i)
        {
            if (!used[i])
            {
                nums[idx] = '0' + i, used[i] = true;
                helper(limit, nums, idx + 1, used, cnt);
                nums[idx] = '0', used[i] = false;
            }
        }
    }

    int countSpecialNumbers(int n)
    {
        string str = to_string(n);
        int m = str.length();

        if (m == 1)
            return n == 0 ? 1 : n;

        // 如果数字长度少于 m 位, k 是组合数
        int res = 9, k = 9;
        for (int i = 2; i < m; ++i)
        {
            res += 9 * k;
            k = k * (10 - i);
        }

        // 数字长度等于 m 位
        // nums[0] < str[0], k = A(9, m - 1)
        if (str[0] >= '2')
            res += (str[0] - '0' - 1) * k;

        // nums[0] == str[0], 需要填充剩余的 m - 1 位
        // 允许使用的字符
        bool used[10] = {false};
        used[str[0] - '0'] = true;

        string nums(m - 1, '0');
        int cnt = 0;
        helper(str.substr(1), nums, 0, used, cnt);
        return res + cnt;
    }
};
posted @   sinkinben  阅读(83)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示