建立免费网站兰溪做网站哪家好
web/
2025/9/27 11:56:31/
文章来源:
建立免费网站,兰溪做网站哪家好,怀安县网站建设,搜索seo神器题目描述
输入一个数n#xff0c;求出 [1, n] 中每个数码出现的次数#xff0c;即0 - 9每个数出现的次数。 解题思路
首先是无情的暴力法#xff0c;可以用于判断我们后续的优化代码是否正确。
import java.io.*;
import java.util.*;public class Main1 {static int n;p…题目描述
输入一个数n求出 [1, n] 中每个数码出现的次数即0 - 9每个数出现的次数。 解题思路
首先是无情的暴力法可以用于判断我们后续的优化代码是否正确。
import java.io.*;
import java.util.*;public class Main1 {static int n;public static void main(String[] args){Scanner sc new Scanner(System.in);int[] cnt new int[10];n sc.nextInt();for (int i 1; i n; i) {int t i;while (t 0) {cnt[t % 10];t / 10;}}System.out.println(Arrays.toString(cnt));}
}
数位dp
用此题来引出数位dp的概念首先我们寻找规律比如0-9所有的一位数字正好包含了所有数码各一次进一步思考在0-99中根据十进制递增的简单规律我们可以发现这10个数字每个数字都出现了相同的次数有一个例外是0它由于一位数字的时候十位的0被省略所以会少一些但我们只需要改变思路变成00-99那么所有数字出现的次数就是完全相等的了。
我们定义 dp[i] 表示 i 位数所有数字出现的次数dp[1] 的值即1dp[2]的值我们应当如何思考呢从00-99考虑每个数有两位总共100个数那么总数字个数就是2*100 200个再平均分配到10个数字那么dp[2]的值即为20个相应的dp[3]的值是3*1000/10 300个。 dp[i] dp[i - 1] * 10 10^(i - 1); 虽然我们可以根据规律推出递推式如上但具体代码中并不需要如此计算我们知道即可。 举例分析
第二步我们考虑一个数367。
我们可以将367划分为以下几个区间[000, 099][100, 199][200, 299][300, 367];
我们考虑计算000-367的原因是这样有利于我们根据前面的dp数组进行计算并且我们会发现一个具有明显规律的bug这个BUG就是多算了很多0而其规律就是可以根据n的位数直接得出我们多算了多少个0最后减掉就可以了。
比如说对于一个个位数8我们考虑[0, 8]则多算了1个0对于一个十位数93我们考虑[00, 93]则多算了11个0对于一个百位数100我们考虑[000, 100]则多算了111个0。
如果还不太能理解则可以从100开始往下并列书写容易发现在百位上[000, 099]多计算了100个0在[000009]的十位上多计算了10个0在[000000]的个位上多计算了1个0构成111个0。 代码设计
我们将[000, 099][100, 199][200, 299]看作具有相同的特性即它们之中都包含了1份[00, 99]他们唯一不同的是第一个区间除此之外多了100个0第二个区间还多了100个1第三个区间还多了100个2那么这就很有利于我们编写代码。
我们从n的最高位开始考虑[000, 299]的数码已经计算出那么跟百位还有关联的则是3字头的数据很明显在[300, 367]中包括了68个3和一个区间[00, 67]那么第二轮循环按照相同的逻辑处理[00, 67]即可。
在下面的代码中我们在init()方法中提前初始化了一些有利于我们计算的数据
ten[i] 表示10的 i 次方的数值cnt[i] 表示数码 i 出现的次数zero 表示最后需要减去的多余的数码0的个数num[i] 表示n的第 i 位数的数值
import java.util.*;public class Main {static long n;static int len 0;static long[] dp, ten, cnt;static long zero;static int[] num;public static void main(String[] args) {Scanner sc new Scanner(System.in);n sc.nextLong();init(n);solve(n);}public static void solve(long n) {cnt new long[10];long num2 n;for (int l len; l 1; l--) {for (int i 0; i 9; i) {cnt[i] num[l] * dp[l - 1];}for (int i 0; i num[l]; i) {cnt[i] ten[l - 1];}num2 - num[l] * ten[l - 1];cnt[num[l]] num2 1;}cnt[0] - zero;for (int i 0; i 9; i) {System.out.print(cnt[i] );}}public static void init(long n) {num new int[15];while (n 0) {num[len] (int) (n % 10);n / 10;}dp new long[len 1];ten new long[len 1];ten[0] 1;for (int i 1; i len; i) {zero zero * 10 1;dp[i] i * ten[i - 1];ten[i] 10 * ten[i - 1];}}
} 题后总结
上述算法基于[1, n]的数码数量对于[n, m]之间的数码数量则可以先计算[1, m]和[1, n-1]再在对应数码位上进行相减即可。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/82752.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!