最大为N的数字组合

给定一个按 非递减顺序 排列的数字数组 digits 。你可以用任意次数 digits[i] 来写的数字。
例如,如果 digits = ['1','3','5'],我们可以写数字,如 '13', '551', 和 '1351315'。
返回 可以生成的小于或等于给定整数 n 的正整数的个数

1. 数位dp

class Solution {
public:
    int atMostNGivenDigitSet(vector<string>& digits, int n) {
        auto s = to_string(n); //转字符串逐位递归分析
        int m = s.length(), memo[m];
        memset(memo,-1,sizeof(memo));
        int notall = 0;
        function<int(int, int, bool)> f = [&](int i,bool prezero,bool is_limit) -> int {//视情况记录已遍历值的某种特征,如1的个数,mask状态,
            if (i == m) return !prezero;
            if (!is_limit&&memo[i]!= -1) //已经存储过,直接剪枝返回
                return memo[i];
            int res = 0; //计算1出现的个数
            if(prezero) notall += f(i+1,prezero,0);//单独处理前导0,同时不受限,含前导零的数需要单独计算
            int up = is_limit ? s[i] - '0' : 9; // 根据受限与否决定枚举数上界
            //做选择
            for (int d = 0; d < digits.size(); d++){ //遍历可选数
                    int cur = digits[d][0]-'0';
                    if(cur>up)  break;//剪枝
                    res += f(i + 1, 0, is_limit && cur == up);//移动到下一位,判断限制情况
            }
            if (!is_limit) //记录非限制数
                memo[i] = res;
            return res;
        };
        return f(0,true,true)+notall;   //从下标0开始,刚开始受限
    }
};
posted @ 2023-06-07 22:28  失控D大白兔  阅读(7)  评论(0编辑  收藏  举报