统计数码出现的个数

2024-04-02 14:36
文章标签 统计 个数 数码

本文主要是介绍统计数码出现的个数,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目描述

输入一个数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] 的值即1,dp[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,在[000,009]的十位上多计算了10个0,在[000,000]的个位上多计算了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.chinasem.cn/article/870238

相关文章

在Linux终端中统计非二进制文件行数的实现方法

《在Linux终端中统计非二进制文件行数的实现方法》在Linux系统中,有时需要统计非二进制文件(如CSV、TXT文件)的行数,而不希望手动打开文件进行查看,例如,在处理大型日志文件、数据文件时,了解... 目录在linux终端中统计非二进制文件的行数技术背景实现步骤1. 使用wc命令2. 使用grep命令

详解如何使用Python从零开始构建文本统计模型

《详解如何使用Python从零开始构建文本统计模型》在自然语言处理领域,词汇表构建是文本预处理的关键环节,本文通过Python代码实践,演示如何从原始文本中提取多尺度特征,并通过动态调整机制构建更精确... 目录一、项目背景与核心思想二、核心代码解析1. 数据加载与预处理2. 多尺度字符统计3. 统计结果可

Pandas中统计汇总可视化函数plot()的使用

《Pandas中统计汇总可视化函数plot()的使用》Pandas提供了许多强大的数据处理和分析功能,其中plot()函数就是其可视化功能的一个重要组成部分,本文主要介绍了Pandas中统计汇总可视化... 目录一、plot()函数简介二、plot()函数的基本用法三、plot()函数的参数详解四、使用pl

Pandas统计每行数据中的空值的方法示例

《Pandas统计每行数据中的空值的方法示例》处理缺失数据(NaN值)是一个非常常见的问题,本文主要介绍了Pandas统计每行数据中的空值的方法示例,具有一定的参考价值,感兴趣的可以了解一下... 目录什么是空值?为什么要统计空值?准备工作创建示例数据统计每行空值数量进一步分析www.chinasem.cn处

Mysql如何将数据按照年月分组的统计

《Mysql如何将数据按照年月分组的统计》:本文主要介绍Mysql如何将数据按照年月分组的统计方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录mysql将数据按照年月分组的统计要的效果方案总结Mysql将数据按照年月分组的统计要的效果方案① 使用 DA

一文详解SQL Server如何跟踪自动统计信息更新

《一文详解SQLServer如何跟踪自动统计信息更新》SQLServer数据库中,我们都清楚统计信息对于优化器来说非常重要,所以本文就来和大家简单聊一聊SQLServer如何跟踪自动统计信息更新吧... SQL Server数据库中,我们都清楚统计信息对于优化器来说非常重要。一般情况下,我们会开启"自动更新

opencv实现像素统计的示例代码

《opencv实现像素统计的示例代码》本文介绍了OpenCV中统计图像像素信息的常用方法和函数,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 统计像素值的基本信息2. 统计像素值的直方图3. 统计像素值的总和4. 统计非零像素的数量

如何使用 Bash 脚本中的time命令来统计命令执行时间(中英双语)

《如何使用Bash脚本中的time命令来统计命令执行时间(中英双语)》本文介绍了如何在Bash脚本中使用`time`命令来测量命令执行时间,包括`real`、`user`和`sys`三个时间指标,... 使用 Bash 脚本中的 time 命令来统计命令执行时间在日常的开发和运维过程中,性能监控和优化是不

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

hdu1496(用hash思想统计数目)

作为一个刚学hash的孩子,感觉这道题目很不错,灵活的运用的数组的下标。 解题步骤:如果用常规方法解,那么时间复杂度为O(n^4),肯定会超时,然后参考了网上的解题方法,将等式分成两个部分,a*x1^2+b*x2^2和c*x3^2+d*x4^2, 各自作为数组的下标,如果两部分相加为0,则满足等式; 代码如下: #include<iostream>#include<algorithm