[纯C]剑指 Offer 43. 1~n 整数中1出现的次数(数位dp解决)

题目:

在这里插入图片描述

数位dp详解

数位dp就是利用数组的深搜实现对0~nums区间内任意数字的连续操作,而dp就是进行了记忆化搜索。

//首先要清楚数位dp的实质:对该数组形式存储的数字,对它的0~nums的所有数字进行相应的操作。这个时候就可想到数位dp。
int a[12];//存储的数字的十进制 位数。
//memo数组用于处理重复性记忆问题(备忘录)。记住还有limit变量用于判断是否被限制状态。
//这里备忘录后面存储count的长度根据需求来,比如输入的十进制数字最大也就10位,则count肯定不会超过10位。
int memo[12][10];//不能再这里直接初始化,不然会出错!!最好写个init函数
//这里的备忘录的含义是:当处于非限制状态的同一层数字情况(相当于p层),且count所记录下的数字相同。
int dp(int p,int count,bool limit){
//撒网到尽头返回该条路径的count,后面由res将网收拢网上继续收网。
    if(p<0) 
        return count ;
//对于既是同层撒网,且网中的初始count相同,并且处于非限制状态的。也就是既是非限制状态又处于备忘录,则可返回。
    if(!limit&&memo[p][count]!=-1)return memo[p][count];
//注意每层(相当于每位)都要刷新res,每一层的结果都是孤立的通过+=联系起来
    int res = 0;
//如果处于限制状态则该位最多取a[p]否则0-9
    int up = limit?a[p]:9;
   	for(int i=0;i<=up;i++){
//每次选该位数字的下一种情况时,重置cur
        int cur = count;
        if(i==1)
            cur++;
        res += dp(p-1,cur,limit && i==a[p]);
    }
    if(!limit) memo[p][count] = res;
    return res;
}
void init(){
    memset(memo,-1,sizeof(memo));
}

//solve函数用于解决该问题。nums低位对应a数组的0位
int solve(int nums){
    int x = nums;
    int p = 0;
    while(x){
        //将数位按数组存储
        a[p++]=x%10;
        x /= 10; 
    }
    return dp(p-1,0,true);
}

int countDigitOne(int n){
    init();
    return solve(n);

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值