• 233. 数字 1 的个数


    给定一个整数 n,计算所有小于等于 n 的非负整数中数字 1 出现的个数。

    示例:

    输入: 13
    输出: 6
    解释: 数字 1 出现在以下数字中: 1, 10, 11, 12, 13 。

    来源:力扣(LeetCode)
    链接:https://leetcode-cn.com/problems/number-of-digit-one

    这题经过lkn大佬的指点,用数位dp的方法还是很简单的,但是需要自己多举几个例子分析一下。

    首先 你需要知道 9以内1的个数有1个, 99以内1的个数有20个,999以内1的个数有300个,也就是说 10的n次方以内不包括10的n次方 1的个数有n*(10^(n-1))个

    比如 1234 如果我们已经知道了dp[2]=154; 也就是234内1的个数有154个,我们要得到dp[3]的值

    dp[3] = 1000以内1的个数(不包括1000) + dp[2] + 235(1xxx都是以1开头,1000~1234有235个数) 

    在比如 2234 

    dp[3] = 1000以内1的个数*2(不包括1000) + dp[2] +1000 (1000~1999有1000个数)

    由此我们可以得出关系表达式 (x表示当前位上的数字)

    dp[i] = 10^(i-1)  * i * x + dp[i-1] + 后i位*(x==1) +10^i*(x>1)

    代码如下:

    int countDigitOne(int n) {
            if(n<0)
            return 0;
            vector<int> dp(100,0);
            int x=n%10;
            int N=n;
            if(x==0)dp[0]=0;
            else dp[0]=1;
            n/=10;
            int i=1;
            long p=10;
            while(n){
                x=n%10;
                if(x==0)dp[i]=dp[i-1];
                else{
                    dp[i]=(N%p+1)*(x==1)+dp[i-1]+(i*pow(10,i-1))*x+p*(x>1);
                }
                n/=10;i++;p*=10;
            }
    
            return dp[i-1];
        }

    类似的题目还有求2的个数

    面试题 17.06. 2出现的次数

    原理相同,稍加修改即可

    int numberOf2sInRange(int n) {
            if(n<1)
            return 0;
            vector<int> dp(100,0);
            int x=n%10;
            int N=n;
            if(x<2)dp[0]=0;
            else dp[0]=1;
            n/=10;
            int i=1;
            long p=10;
            while(n){
                x=n%10;
                if(x==0)dp[i]=dp[i-1];
                else{
                    dp[i]=(N%p+1)*(x==2)+dp[i-1]+(i*pow(10,i-1))*x+p*(x>2);
                }
                n/=10;i++;p*=10;
            }
    
            return dp[i-1];
        }

    牛客网上有一道通过率为0.00%的题目,我很好奇为啥竟然没有人做出来,然后就作死尝试了一下,因为它就是求n以内1和2的个数和,但是官方给的检测通不过,还说99以内1的个数加2的个数是42,简直了,,,,

    https://www.nowcoder.com/practice/20d6abf0fbcc49a799024e61fa2292c6?tpId=40&tqId=30988&tPage=1&rp=1&ru=/ta/kaoyan&qru=/ta/kaoyan/question-ranking

    题目描述

    给定正整数N,函数F(N)表示小于等于N的自然数中1和2的个数之和,例如:1,2,3,4,5,6,7,8,9,10序列中1和2的个数之和为3,因此 F(10)=3。输入N,求F(N)的值,1=<N<=10^100(10的100次方)若F(N)很大,则求F(N)mod20123的值

    我寻思不就是把整数用字符串存起来。。。

    #include<iostream>
    #include<stdio.h>
    #include<cmath>
    #include<cstring>
    #include<vector>
    using namespace std;
    #define MM 20123
    
    int f1(string n, int k){
        int res=0;
        for(int i=n.length()-k;i<n.length();i++)
        {
            res=(res*10+n[i]-'0')%MM;
        }
        return res;
    }
    
    int f2(int k){
        int res=1;
        for(int i=0;i<k;i++){
            res=res*10%MM;
        }
        return res;
    }
    
    int countDigitOneMod(string num) {
            int n=num.length();
            if(num[0]=='-')
                return 0;
            vector<int> dp(110,0);
            char x=num[n-1];
            if(x=='0')dp[0]=0;
            else dp[0]=1;
            int i=1;
            while(i<n){
                x=num[n-i-1];
                if(x=='0')dp[i]=dp[i-1];
                else{
                    int k=f1(num,i);
                    int t=(f2(i-1)*i*(x-'0'))%MM;
                    dp[i]=(k+1)*(x=='1')+dp[i-1]%MM+t+f2(i)*(x>'1');
                    dp[i]=dp[i]%MM;
                }
                i++;
            }
            return dp[i-1];
        }
    
    int countDigitTwoMod(string num) {
            int n=num.length();
            if(num[0]=='-')
                return 0;
            vector<int> dp(110,0);
            char x=num[n-1];
            if(x<'2')dp[0]=0;
            else dp[0]=1;
            int i=1;
            while(i<n){
                x=num[n-i-1];
                if(x=='0')dp[i]=dp[i-1];
                else{
                    int k=f1(num,i);
                    int t=(f2(i-1)*i*(x-'0'))%MM;
                    dp[i]=(k+1)*(x=='2')+dp[i-1]%MM+t+f2(i)*(x>'2');
                    dp[i]=dp[i]%MM;
                }
                i++;
            }
    
            return dp[i-1];
        }
    
    int main(){
        string N;
        while(cin>>N){
            int b=countDigitOneMod(N);
            int c=countDigitTwoMod(N);
            cout<<(b+c)%MM<<endl;
        return 0;
    }

    代码我验证过,反正long那么大的n验算答案是对的,但是牛客网的答案不一样,罢了罢了

  • 相关阅读:
    PHP返回XML与JSON数据
    Canvas学习-1
    PHP与cURL
    PHP调用SOAP Webservice
    Ubuntu查找文件是否安装
    API Centeric Web Application论文
    Git学习2
    An invalid character [32] was present in the Cookie value
    关于eclipse项目的x号报错的一些问题
    关于eclipse的项目前有感叹号和errors exist in required project相关问题
  • 原文地址:https://www.cnblogs.com/Dancing-Fairy/p/12682635.html
Copyright © 2020-2023  润新知