2376. 统计特殊整数--(每日一难phase2--day4)

2376. 统计特殊整数

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

给你一个 正 整数 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 * 1e9

分析:

  • 采用数位dp方式,之所以可以采用dp方式,是由于在组合数字过程中会出现重复现象(并不是相同的数字,是等价的数字)例如:n=53241;52*** ,51***这时就是等价情况,52,51都是已经消除了限制,后边的三个数存在的情况一样,因此可以使用dp;
  • 限制是什么意思?52 ,51都是已经消除了限制,后边的数可以任意组合,但是53***没有消除限制,第三位必须为2或者4数字,也就是说,如果在某位已经消除限制,后边数字组合就是等价的
  • 通过mask判断数字是否使用过:最多数字为10位(0-9),1<<10得到100,0000,0000,每一位表示一个数字。如果2已经使用,mask变为100,0000,0010(将第二位变为1)。
  • 位运算技巧:将某位(假设为d位)变为1,先得到一个d位为1的数,也就是1<
  • 位运算技巧:将某位(假设为d位)变为0,先得到一个d位为1的数,也就是1<
  • 位运算技巧:查看某一位(假设为d位),首先将数右移d位,将第d位移到最后一位,然后&1(除了第一位其他位全为0,0001&1111=0001),如果原来结果为1,则与的结果为1,如果原来结果为0,则0&1=0;

code:

class Solution {
public:
    int countSpecialNumbers(int n) {
        auto s = to_string(n);
        int m = s.length(), dp[m][1 << 10];
        memset(dp, -1, sizeof(dp));
        // 记忆化搜索
        function<int(int, int, bool, bool)> f = [&](int i, int mask, bool is_limit, bool is_num) -> int {
            if (i == m) 
                return is_num;
            if (!is_limit && is_num && dp[i][mask] >= 0) 
                return dp[i][mask];
            int res = 0;
            if (!is_num) 
                res = f(i + 1, mask, false, false); // 可以跳过当前数位
            // 1 - is_num 表示如果前边已经出现数字,is_num=true ,可以从0枚举;如果不是数字则从1枚举
            // up = is_limit ? s[i] - '0' : 9; 如果前边的数字都和最大值n的数字相同,下一位的最大值应该为第i位数字
            for (int d = 1 - is_num, up = is_limit ? s[i] - '0' : 9; d <= up; ++d) // 枚举要填入的数字 d
                if ((mask >> d & 1) == 0) // d 不在 mask 中
                    res += f(i + 1, mask | (1 << d), is_limit && d == up, true);
            // 有限制时应该到限制位之后才能记忆,
            //并且前边应该有数字才能记忆,如果前边没有数字用不到这个记忆
            // 能用到记忆的情况:n=54321;52341 52***这时能用到记忆,记忆的是前边数字一样,顺序不同,限制已经消除的情况
            // 0002,前边i位都为0只会出现一次,因此不用记忆。
            if (!is_limit && is_num) dp[i][mask] = res;
            return res;
        };
        return f(0, 0, true, false);
    }
};

代码来源:leetcode
视频链接:视频讲解

你可能感兴趣的:(每日一难,算法,leetcode,职场和发展)