题目套路
这类题目一般的描述为,在[L,R]区间内满足某个条件的数字的个数
参照:灵神的讲解
模板讲解
数位dp的核心在于空间换时间,利用缓存保存前面部分的状态
数位dp递归函数一般以下的定义:
fun(int i, int mask, bool isLimit, bool isNum)
其中:
- i:表示当前遍历到第 i 位
- mask 表示前面选过的数字集合,换句话说,第 i 位要选的数字不能在 mask中。
- isLimit 表示前面一位数是否到顶,比如题目限制的数字是4321(下标从左边0开始),当我遍历到第1位时,假如此时isLimit = false,说明第 0 位取的数小于4,不妨设选的时3,那么这时第 1 位可以选[0,9],否则如果isLimit = true,说明第 0 位取4,这时第 1 位是能取[0,3],不然就会超过题目要求的范围
- isNum表示前一位是否有取值,true代表取了,否则没有取,这个主要是用于防止前导0的出现
模板代码
int numberOf2sInRange(int n) {
string str = to_string(n);
int len = str.size();
int di[len][limit]; //limit根据题目要求具体取值
memset(dp, -1, sizeof(dp));
function<int(int,int,bool,bool)> fun = [&](int i, int mask, bool is_limit, bool pre_fill) ->int {
if(i==len) return ......;
if(!is_limit && pre_fill && dp[i][mask]!=-1) return dp[i][mask];
int ret = 0;
if(!pre_fill) ret += fun(i+1, time, false, false);
int up = is_limit ? (str[i]-'0') : 9;
for(int d=pre_fill?0:1; d<=up; d++) {
ret += fun(i+1, .....(根据题目选择下一步的状态), is_limit&&d==up, true);
}
if(!is_limit && pre_fill)
dp[i][mask] = ret;
return ret;
};
return fun(0, 0, true, false);
}