统计数码出现的个数

题目描述

输入一个数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.mzph.cn/news/787343.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iOS系统文件备份与还原:保护和管理手机中的关键数据

​ 目录 引言 用户登录工具和连接设备 查看设备信息&#xff0c;电池信息 查看硬盘信息 硬件信息 查看 基带信息 销售信息 电脑可对手机应用程序批量操作 运行APP和查看APP日志 IPA包安装测试 注意事项 引言 苹果手机与安卓手机不同&#xff0c;无法直接访问系统文件…

Chatgpt掘金之旅—有爱AI商业实战篇|文案写作|(三)

演示站点&#xff1a; https://ai.uaai.cn 对话模块 官方论坛&#xff1a; www.jingyuai.com 京娱AI 一、前言 人工智能&#xff08;AI&#xff09;技术作为当今科技创新的前沿领域&#xff0c;为创业者提供了广阔的机会和挑战。随着AI技术的快速发展和应用领域的不断拓展&…

#设计模式#4.6 Flyweight(享元) 对象结构型模式

享元模式是一种结构型设计模式&#xff0c;其主要目标是通过共享大量细粒度的对象来节省内存。享元模式的关键在于区分内部状态&#xff08;Intrinsic State&#xff09;和外部状态&#xff08;Extrinsic State&#xff09;。 内部状态是对象可共享的部分&#xff0c;通常是对…

是否应该升级到ChatGPT 4.0?深度对比ChatGPT 3.5与4.0的差异

如果只是想简单地体验AI的魅力&#xff0c;感受大模型的独特之处&#xff0c;或是玩一玩文字游戏&#xff0c;那么升级至ChatGPT 4.0可能并非必需。然而&#xff0c;若你期望将AI作为提升工作学习效率的得力助手&#xff0c;那么我强烈建议你升级到ChatGPT 4.0。 如果你不知道…

Linux和Windows安装PHP依赖管理工具Composer

Composer 是 PHP 的一个依赖管理工具。它允许申明项目所依赖的代码库&#xff0c;会在项目中安装它们。 Composer 不是一个包管理器。是的&#xff0c;它涉及 "packages" 和 "libraries"&#xff0c;但它在每个项目的基础上进行管理&#xff0c;在你项目的…

【Springboot整合系列】SpringBoot整合WebService

目录 Web服务介绍Web服务的两种类型Web服务架构Web服务的主要特点Web服务使用场景Web服务标准和技术 WebService介绍WebService的作用适用场景不适用场景 WebService的原理三个角色相关概念 WebService开发框架代码实现服务端1.引入依赖2.实体类3.业务层接口接口实现类 4.配置类…

python对接百度云车牌识别

注册百度智能云&#xff0c;选择产品服务。 https://console.bce.baidu.com/ 每天赠送200次&#xff0c;做开发测试足够了。 在应用列表复制 AppID , API Key ,Secret Key 备用。 SDK下载地址 https://ai.baidu.com/sdk#ocr 下载SDK文件&#xff0c;解压&#xff0c;…

matlab中旋转矩阵函数

文章目录 matlab里的旋转矩阵、四元数、欧拉角四元数根据两向量计算向量之间的旋转矩阵和四元数欧拉角转旋转矩阵旋转矩阵转欧拉角旋转矩阵转四元数参考链接 matlab里的旋转矩阵、四元数、欧拉角 旋转矩阵dcmR四元数quatq[q0,q1,q2,q3]欧拉角angle[row,pitch,yaw] % 旋转矩阵…

前端跨页面通信方案介绍

在浏览器中&#xff0c;我们可以同时打开多个Tab页&#xff0c;每个Tab页可以粗略理解为一个“独立”的运行环境&#xff0c;即使是全局对象也不会在多个Tab间共享。然而有些时候&#xff0c;我们希望能在这些“独立”的Tab页面之间同步页面的数据、信息或状态。这就是本文说说…

算法学习——LeetCode力扣动态规划篇2(343. 整数拆分、96. 不同的二叉搜索树、416. 分割等和子集、1049. 最后一块石头的重量 II)

算法学习——LeetCode力扣动态规划篇2 343. 整数拆分 343. 整数拆分 - 力扣&#xff08;LeetCode&#xff09; 描述 给定一个正整数 n &#xff0c;将其拆分为 k 个 正整数 的和&#xff08; k > 2 &#xff09;&#xff0c;并使这些整数的乘积最大化。 返回 你可以获得…

构建第一个JS应用(FA模型)

创建JS工程 若首次打开DevEco Studio&#xff0c;请点击Create Project创建工程。如果已经打开了一个工程&#xff0c;请在菜单栏选择File > New > Create Project来创建一个新工程。选择Application应用开发&#xff08;本文以应用开发为例&#xff0c;Atomic Service对…

openGauss 分布式数据库能力

分布式数据库能力 可获得性 本特性自openGauss 2.1.0版本开始引入。 特性简介 基于分布式中间件shardingsphere使openGauss具备分布式数据库能力。使用32个鲲鹏920(128核)节点组网(1*shardingsphere-proxy ,11*shardingsphere-jdbc,20*openGauss)时&#xff0c;完美shardin…

【网络基础】一文搞懂,什么是三次握手与四次挥手

文章目录 三次握手过程为什么要三次握手而不是两次握手呢&#xff1f; 四次挥手过程为什么客户端需要等待超时时间&#xff1f;为什么要四次挥手&#xff1f; 参考 三次握手过程 当客户端向服务端发起连接时&#xff0c;会先发一包 SYN 包连接请求数据&#xff0c;进行询问&am…

【智能算法】蜣螂优化算法(DBO)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2022年&#xff0c;Xue等人受到自然界中蜣螂生存行为启发&#xff0c;提出了蜣螂优化算法&#xff08;Dung beetle optimizer, DBO&#xff09;。 2.算法原理 2.1算法思想 DBO模拟了自然界蜣螂种…

基于8086温度监控报警系统设计

**单片机设计介绍&#xff0c;基于8086温度监控报警系统设计 文章目录 一 概要二、功能设计设计思路 三、 软件设计原理图 五、 程序六、 文章目录 一 概要 基于8086的温度监控报警系统设计概要主要涵盖了该系统的基本组成、工作原理、设计特点以及应用前景等方面。以下是对该…

HarmonyOS 应用开发之RelationalStore开发

场景介绍 RelationalStore提供了一套完整的对本地数据库进行管理的机制&#xff0c;对外提供了一系列的增、删、改、查等接口&#xff0c;也可以直接运行用户输入的SQL语句来满足复杂的场景需要。 基本概念 谓词&#xff1a;数据库中用来代表数据实体的性质、特征或者数据实体…

HTTP响应头和请求头信息对照

HTTP请求头提供了关于请求&#xff0c;响应或者其他的发送实体的信息。HTTP的头信息包括通用头、请求头、响应头和实体头四个部分。每个头域由一个域名&#xff0c;冒号&#xff08;:&#xff09;和域值三部分组成。 通用头标&#xff1a;即可用于请求&#xff0c;也可用于响应…

字典树基础(Java实现)

字典树也叫Trie&#xff0c;是一种树形结构&#xff0c;其中每个节点可以存储一些变量表示该字符串出现的数量。每条边表示一个字符&#xff0c;如节点9存储一个变量cnt&#xff0c;说明存在三个字符串为“cbc” 例题&#xff1a;前缀判定 import java.math.BigInteger; impor…

set/ multiset 容器(二)

一、set查找和统计 函数原型&#xff1a; find(key); //查找key是否存在,若存在&#xff0c;返回该键的元素的迭代器&#xff1b;若不存在&#xff0c;返回 set.end(); count(key); //统计key的元素个数代码示例&#xff1a; #include<iostream> using namespace std;…

【Java入门教程】第十八讲:String类的常见操作及其应用

Java是一种广泛使用的编程语言&#xff0c;它的标准库中包含了大量的类和方法&#xff0c;以支持各种编程任务。在这些类中&#xff0c;String类无疑是最常用、最重要的类之一。 String类在Java中用于表示和操作字符串&#xff0c;即字符序列。本文将详细介绍String类的基本概…