Digits counting

Digits counting

  • from high bit to low bit
// ref: https://leetcode.cn/discuss/post/tXLS3i/
// 代码示例:返回 [low, high] 中的恰好包含 target 个 0 的数字个数
// 比如 digitDP(0, 10, 1) == 2
// 要点:我们统计的是 0 的个数,需要区分【前导零】和【数字中的零】,前导零不能计入,而数字中的零需要计入
int digitDP(int low, int high, int target) {
    string low_s = to_string(low);
    string high_s = to_string(high);
    int n = high_s.size();
    int diff_lh = n - low_s.size();
    vector memo(n, vector<int>(target + 1, -1));

    auto dfs = [&](this auto&& dfs, int i, int cnt0, bool limit_low, bool limit_high) -> int {
        if (cnt0 > target) {
            return 0; // 不合法
        }
        if (i == n) {
            return cnt0 == target;
        }

        if (!limit_low && !limit_high && memo[i][cnt0] >= 0) {
            return memo[i][cnt0];
        }

        int lo = limit_low && i >= diff_lh ? low_s[i - diff_lh] - '0' : 0;
        int hi = limit_high ? high_s[i] - '0' : 9;

        int res = 0;
        int d = lo;
        // 通过 limit_low 和 i 可以判断能否不填数字,无需 is_num 参数
        // 如果前导零不影响答案,去掉这个 if block
        if (limit_low && i < diff_lh) {
            // 不填数字,上界不受约束
            res = dfs(i + 1, cnt0, true, false);
            d = 1;
        }
        for (; d <= hi; d++) {
            // 统计 0 的个数
            res += dfs(i + 1, cnt0 + (d == 0), limit_low && d == lo, limit_high && d == hi);
            // res %= MOD;
        }

        if (!limit_low && !limit_high) {
            memo[i][cnt0] = res;
        }
        return res;
    };

    int ans = dfs(0, 0, true, true);
    return ans;
}