统计数码出现的个数

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

相关文章

SQL Server中,查询数据库中有多少个表,以及数据库其余类型数据统计查询

sqlserver查询数据库中有多少个表 sql server 数表:select count(1) from sysobjects where xtype='U'数视图:select count(1) from sysobjects where xtype='V'数存储过程select count(1) from sysobjects where xtype='P' SE

剑指Offer—编程题10(二进制中1 的个数)

代码如下,请在JDK7及以上版本运行: public class Test10 {/*** 请实现一个函数, 输入一个整数,输出该数二进制表示中1的个数。* 例如把9表示成二进制是1001 ,有2位是1. 因此如果输入9,该出2。** @param n 待的数字* @return 数字中二进制表表的1的数目*/public static int numberOfOne(int

统计是一门艺术(点估计)

1 点估计 1.1 点估计理解(point estimate) 总体,样本属于参数空间 一般未知,要由样本对作一个估计,或对作一个估计,这种估计称为点估计 通常用记为的一个点估计。 1.2 点估计的方法 (1)矩估计: 就是用样本矩来代替总体矩,当然有好有坏 设为总体的一个简单随机样本,, 分别称, 为k阶样本原点矩和k阶样本中心矩. 记 为什么能用矩估计?

金蝶盘点机PDA进行工序汇报扫描,工时工资统计使用说明书

使用盘点机PDA扫描商品条码(序列号)进行工序汇报,自动生成电脑里的【工序汇报单】,自动计算工时,工资。这样就不用去电脑上人工手工一行行录单,大大提高工作效率和数据准确性。 操作时,只需要商品条码(序列号)即可实现快速,准确的工序汇报。从而防止电脑进行工序汇报耗时,费事,不准确的问题。 注意商品条码规则:产品代码+钢管长度+炉号+管号+合同号+序列号 下面我们看下【工序汇报单】的操作步骤

地推利器Xinstall:全方位二维码统计,打造高效地推策略,轻松掌握市场脉搏!

在移动互联网时代,地推作为一种传统的推广方式,依然占据着重要的地位。然而,随着市场竞争的加剧,地推也面临着诸多挑战,如如何有效监测下载来源、解决填码和人工登记的繁琐、避免重复打包和iOS限制、以及如何准确考核推广业绩等。针对这些痛点,Xinstall作为一款强大的移动应用统计与推广平台,推出了全面的地推二维码统计功能,助力地推人员轻松应对各种挑战。 一、一键生成统计二维码,告别繁琐填码 地推

php字符串计算汉字、中英文数字个数

$str = '123abcDEF测试的事发地点';$length = strlen(preg_replace('/[\x00-\x7F]/', '', $str));$arr['en'] = strlen( $str) - $length; //(非中文)$arr['cn'] = intval($length / 3); // 编码GBK,除以2 (中文)print_r($

吴恩达教程以及《统计学习方法》学习笔记

之前都在有道云笔记写的,CSDN不能上传文件,搬运过来实在比较耗费精力,在此给出分享链接: 1、吴恩达教程 2、统计学习方法

36 - 按分类统计薪水(高频 SQL 50 题基础版)

36 - 按分类统计薪水 -- 方法一select'Low Salary' category,sum(income <20000) accounts_count fromAccounts unionselect'Average Salary' category,sum(income between 20000 and 50000) accounts_count fromA

【Rust日报】 2020-1-30 r/rust 频道的数据统计

r/rust 频道的数据统计 在过去的一年左右的时间里,reddit.com 的 r/rust 频道的订阅人数约为过去六年的总和。 数据源:https://subredditstats.com/r/rust Reddit 上参与讨论:https://www.reddit.com/r/rust/comments/ew1i8w/in_the_last_year_or_so_rrust_gained

Python统计实战:一题搞定多元线性回归、共线性、相对重要性分析

为了解决特定问题而进行的学习是提高效率的最佳途径。这种方法能够使我们专注于最相关的知识和技能,从而更快地掌握解决问题所需的能力。 (以下练习题来源于《统计学—基于Python》。联系获取完整数据和Python源代码文件。) 练习题 为了分析影响不良贷款的因素,一家商业银行在所属的多家分行中随机抽取25家,得到的不良贷款、贷款余额、应收贷款、贷款项目个数、固定资产投资等有关数据如下(前3行