首页 > 其他分享 >【剑指 Offer】 43. 1~n 整数中 1 出现的次数

【剑指 Offer】 43. 1~n 整数中 1 出现的次数

时间:2023-05-03 16:34:41浏览次数:29  
标签:10 digit cur Offer 43 整数 high 次数 low

【题目】

输入一个整数 n ,求1~n这n个整数的十进制表示中1出现的次数。

例如,输入12,1~12这些整数中包含1 的数字有1、10、11和12,1一共出现了5次。

 

示例 1:

输入:n = 12
输出:5

示例 2:

输入:n = 13
输出:6

 

限制:

    1 <= n < 2^31

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/1nzheng-shu-zhong-1chu-xian-de-ci-shu-lcof
【思想】

解题思路:

将 1 ~n 的个位、十位、百位、...的 1 出现次数相加,即为 1 出现的总次数。

设数字 n 是个 x 位数,记 n的第 i 位为 ni ,则可将 n 写为 nxnx−1⋯n2n1:

    称 " ni​ " 为 当前位 ,记为 cur ,
    将 " ni−1ni−2⋯n2n1​ " 称为 低位 ,记为 low ;
    将 " nxnx−1⋯ni+2ni+1 " 称为 高位 ,记为 high 。
    将 10i称为 位因子 ,记为 digit。

某位中 1出现次数的计算方法:

根据当前位 curcur 值的不同,分为以下三种情况:

    当 cur=0时: 此位 1 的出现次数只由高位 high 决定,计算公式为:

high×digit

    如下图所示,以 n=2304 为例,求 digit=10(即十位)的 1出现次数。



    当 cur=1 时: 此位 1 的出现次数由高位 high和低位 low 决定,计算公式为:

high×digit+low+1

    如下图所示,以 n=2314 为例,求 digit=10 (即十位)的 1出现次数。

 



    当 cur=2,3,⋯ ,9 时: 此位 1 的出现次数只由高位 high决定,计算公式为:

(high+1)×digit

    如下图所示,以 n=2324为例,求 digit=10 (即十位)的 1 出现次数。

 


变量递推公式:

设计按照 “个位、十位、...” 的顺序计算,则 high/cur/low/digit应初始化为:

high = n // 10
cur = n % 10
low = 0
digit = 1 # 个位

举例

以2593为例,例子挺经典,k为5
从最后一位开始,cur表示当前位的值依次为3,9,5,2,high,low分别表示cur的前后,比如:
cur为9,high=25,low=3
下面开始分析:

cur = 3,high=259,low=0,[1,3]中不可能出现5,所以前缀只能取0,1,2,3...258,取不到259,所以5在个位出现了259次.
cur = 9,high = 25,low=3,[1-93]中可以出现5x,所以前缀可以0,1,2,3....25,5在10位出现了26x10=260次.
cur = 5,high = 2,low=93,[1-593]中可以出现5xx,所以前缀可以0,1,2,但是前缀为2时,5xx<=593,不是一个完整的序列,5在百位出现了2x100+93+1次,(为啥加1呢,0-93是94次,所以加1)
cur = 2,high = 0,low=593,[1-2593]中不能出现5xxx,因此5在千位0次.
总结规律:
base = 10^(i-1)
cur >k,结果为 (high+1)*base
cur ==k,结果为 (high)base + low + 1
cur < k,结果为 highbase

 

【代码】

class Solution {
    public int countDigitOne(int n) {
        int digit = 1, res = 0;
        int high = n / 10, cur = n % 10, low = 0;
        while(high != 0 || cur != 0) {
            if(cur == 0) res += high * digit;
            else if(cur == 1) res += high * digit + low + 1;
            else res += (high + 1) * digit;
            low += cur * digit;
            cur = high % 10;
            high /= 10;
            digit *= 10;
        }
        return res;
    }
}

 

标签:10,digit,cur,Offer,43,整数,high,次数,low
From: https://www.cnblogs.com/End1ess/p/17369219.html

相关文章

  • 异或:计算整数0~5的累计异或的3种方式
      #示例10-11计算整数0~5的累计异或的3种方式importfunctoolsimportoperator#方法1:n=0foriinrange(1,6):n^=iprint(n)#方法2:x1=functools.reduce(lambdaa,b:a^b,range(6))print(x1)#方法3:x2=functools.reduce(operator.xor,ra......
  • 剑指 Offer II 022. 链表中环的入口节点
    题目链接:剑指OfferII022.链表中环的入口节点方法一:哈希解题思路统计走过的节点,当第一次遇到重复的节点时,即为入口节点,否则为\(null\)。代码classSolution{public:ListNode*detectCycle(ListNode*head){unordered_map<ListNode*,bool>cache;......
  • 剑指 Offer II 020. 回文子字符串的个数
    题目链接:剑指OfferII020.回文子字符串的个数方法一:动态规划解题思路状态表示:\(dp[i][j]\)表示子字符串\(s[i,j]\)是否为回文串;状态计算:若\(s[i]\)!=\(s[j]\),显然不是;若\(s[i]\)==\(s[j]\),有以下几种可能:\(i\)==\(j\),只有一个字符,是回文串;\(i\)+\(1\)......
  • unity发布到4399的webgl模式问题:FRAMEWORK.JS中的WEBREQUEST_SEND括号内的函数(不能有
    在发布4399的时候,之前遇到过这个问题,解决方法当然就是删除这个函数啦。步骤也很简单,但是刚开始摸不着头脑搞了好久,最后发现发布的时候有个加密选项,选择不加密,后面build的文件里面就可以进行打开修改,按照要求修改函数即可。......
  • 2023-05-02:如果一个正整数每一个数位都是 互不相同 的,我们称它是 特殊整数 。 给你一
    2023-05-02:如果一个正整数每一个数位都是互不相同的,我们称它是特殊整数。给你一个正整数n,请你返回区间[1,n]之间特殊整数的数目。输入:n=20。输出:19。答案2023-05-02:可以通过数字组合和状态压缩的动态规划算法来解决。具体过程如下:1.对于给定的正整数n,求出其位数......
  • 【剑指 Offer】 14- II. 剪绳子 II
    【题目】给你一根长度为n的绳子,请把绳子剪成整数长度的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1]...k[m-1]。请问k[0]*k[1]*...*k[m-1]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。答案需要......
  • 2023-05-01:给你一个整数 n , 请你在无限的整数序列 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1
    2023-05-01:给你一个整数n,请你在无限的整数序列[1,2,3,4,5,6,7,8,9,10,11,...]中找出并返回第n位上的数字。1<=n<=2^31-1。输入:n=11输出:0解释:第11位数字在序列1,2,3,4,5,6,7,8,9,10,11,...里是0,它是10的一部分。答案2023-05-01:该......
  • 2023-05-01:给你一个整数 n , 请你在无限的整数序列 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1
    2023-05-01:给你一个整数n,请你在无限的整数序列[1,2,3,4,5,6,7,8,9,10,11,...]中找出并返回第n位上的数字。1<=n<=2^31-1。输入:n=11输出:0解释:第11位数字在序列1,2,3,4,5,6,7,8,9,10,11,...里是0,它是10的一部分。答案2023-05-01:......
  • Codeforces Gym 103439D - LIS Counting(猜结论+状压)
    一道需要一些猜结论技巧的中档题。首先突破口在于排列长度恰好等于不是额外输入的某个数\(k\)而是LDS与LIS的乘积,这显然启示我们去找一些性质。根据dilworth定理,最长反链等于最小链覆盖,故LIS的长度,就是最少需要的递减数列的个数使得每个元素被覆盖至少一次,而每个递减数......
  • 时间转化Fri Apr 07 11:43:24 +0800 2022
    原格式:FriApr0711:43:24+08002022灵感:获取微博某时间段到...之间的内容转化格式:2022-04-07#实现importdatetimedate_str="FriApr0711:43:24+08002022"date=datetime.datetime.strptime(date_str,"%a%b%d%H:%M:%S%z%Y")formatted_date=date.str......