编程语言
首页 > 编程语言> > 力扣233(java)-数字1的个数(困难)

力扣233(java)-数字1的个数(困难)

作者:互联网

题目:

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

 

示例 1:

输入:n = 13
输出:6
示例 2:

输入:n = 0
输出:0
 

提示:

0 <= n <= 109

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/number-of-digit-one
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解题思路:

这个题是真的很打脑壳啊~参考【 liweiwei1419】和 【2021293707L2】的题解,谢谢大佬!

主要运用数位dp的思路,采用【自底向上】的递推求解,实际是【动态规划】关于数位的入门问题。

题目的意思是:在1~n 的所有整数中出现1的个数,不是整数的个数,而是整数中包含的1的个数!

例如:15

包含1的整数有:1, 10, 11, 12, 13, 14, 15, 一共有 1 + 1 + 2  + 1 + 1 + 1 + 1 = 8 ,所以1~15的所有整数中一共包含8个1。

数位:是把一个数按照个位、十位、百位拆开来看。因此本题就可以拆分为:个位出现1的个数、十位出现1的个数、百位出现1的个数...

定义状态1:A[i] 表示0~10i+1-1的所有i+1位数里1的总数。

例如:

根据上述规律,总结归纳出:A[i]= 10 * A[i -1 ] +10i

定义状态2:dp[i]表示:从右向左数截取到第 i + 1位到最后一个数组成的数字里面包含1的总个数。

例如:2875

因此从右向左遍历 给定整数n的每一位 i ,假设当前遍历到的数是m(0 <= m <= 9),根据遍历到的数值进行分类讨论:

dp[0]代表的是个位数包含的1的个数,如果m =0,表示个位数为0即dp[0] == 0,当m==0~9时,这10个数只有一个1即dp[0] == 1

代码:

 1 class Solution {
 2     public int countDigitOne(int n) {
 3         //将整数转换成字符串
 4         String s = String.valueOf(n);
 5         char[] ca = s.toCharArray();
 6         int m = s.length();
 7         //如果只有个位数则只包含一个1
 8         if(m == 1){
 9             return n == 0 ? 0 : 1;
10         }
11         //求状态1:A[i]: 0~10^(i+1) -1包含1的个数
12         //0~9,0~99,0~999
13         //如果是5位数,只需要求0~9999中出现1的个数
14         int[] A = new int[m-1];
15         // 0~9
16         A[0] = 1;
17         for(int i = 1; i < m-1; i++){
18             A[i] = 10 * A[i-1] + (int) Math.pow(10, i);
19         }
20         //求状态2:dp[i]
21         int[] dp = new int[m];
22         //如果最后一位为0
23         if(ca[m - 1] == '0'){
24             dp[0] = 0;
25         }else{
26         //最后一位不为0,即为0~9
27           dp[0] = 1;
28         }
29         for(int i = 1; i < m; i++){
30             //从右向左截取每一数位
31             char currChar = ca[m - i - 1];
32             if (currChar == '0'){
33                 //当前位为0,状态值取决于它右边的1的个数
34                 dp[i] = dp[i - 1];
35             } else if (currChar == '1'){
36                 //最高位为1,分为三个步骤相加
37                 //例如166,其次:求出100~166中元素1的个数
38                 int res = Integer.parseInt(s.substring(m - i, m)) + 1;
39                 //166中0~66,和小于100d 0~99中1的个数
40                 dp[i] = res + dp[i-1] + A[i-1];
41             }else{
42                 //最高位大于1的情况,例如465
43                 //最高位不是1个数,dp[i-1]
44                 //最高位是1,即为10^i
45                 //算其他模块:m * A[i-1]
46                dp[i] = (currChar - '0') * A[i-1] + dp[i-1] + (int) Math.pow(10,i);
47             }
48         }
49         return dp[m - 1];
50     }
51 }

标签:10,java,int,个数,力扣,99,100,dp,233
来源: https://www.cnblogs.com/liu-myu/p/16582849.html