HDOJ ACM 1017题目一般是求解“数字统计”类问题,常见题目是统计某个数字在1到n范围内出现的次数。
下面给你一个Java版本的思路与代码示例,帮助你理解和实现。
题目描述(常见版本)
统计数字d
在从1
到n
的所有整数中出现的总次数。
比如:
- 输入:
n=12, d=1
- 输出:
5
(数字1在1,10,11,12中出现,总共5次)
解决思路
最直接的思路:
- 遍历
1
到n
的每个数字 - 将数字转换为字符串,统计其中字符
d
出现的次数 - 累加计数
这种方法简单但当n
很大时效率低。
Java代码示例(暴力法)
import java.util.Scanner;
public class ACM1017 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextInt()) {
int n = sc.nextInt();
int d = sc.nextInt();
if (n == 0 && d == 0) break;
int count = 0;
String digitStr = String.valueOf(d);
for (int i = 1; i <= n; i++) {
count += countDigitInNumber(i, digitStr);
}
System.out.println(count);
}
sc.close();
}
// 统计数字num中digit出现次数
public static int countDigitInNumber(int num, String digit) {
int cnt = 0;
String s = String.valueOf(num);
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == digit.charAt(0)) cnt++;
}
return cnt;
}
}
进阶优化(数学方法)
对于很大的n
,暴力法效率太低,通常用数学计数方法,分析每一位上数字出现次数。
这里先给暴力法,如果需要我可以帮你写数学优化版。
好的!下面给你写一个基于数学计数方法的优化版 Java 解法,能高效统计数字 d 在 1 到 n 范围内出现的次数。
思路说明
对于每一位(个位、十位、百位…)分别计算数字 d 出现的次数:
- 计算当前位置上的高位、当前位、低位的值
- 根据当前位的数字和 d,计算该位 d 出现的次数
优化代码示例
import java.util.Scanner;
public class ACM1017_Optimized {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNextInt()) {
int n = sc.nextInt();
int d = sc.nextInt();
if (n == 0 && d == 0) break;
int count = countDigit(n, d);
System.out.println(count);
}
sc.close();
}
// 统计数字d在1到n中出现的次数
public static int countDigit(int n, int d) {
int count = 0;
int factor = 1; // 当前位的权重,比如个位是1,十位是10,百位是100
while (n / factor != 0) {
int high = n / (factor * 10);
int cur = (n / factor) % 10;
int low = n % factor;
if (cur > d) {
count += (high + 1) * factor;
} else if (cur == d) {
count += high * factor + low + 1;
} else {
count += high * factor;
}
// 特殊情况:d == 0时,最高位不能算0开头的数字
if (d == 0) {
count -= factor;
}
factor *= 10;
}
return count;
}
}
代码说明
factor
表示当前位的权重,依次为 1、10、100 …high
是当前位高位部分的数字cur
是当前位的数字low
是当前位低位部分的数字- 根据
cur
与d
的大小关系计算当前位数字d
出现次数 - 特别处理
d=0
,避免计数错误(因为没有数字是以0开头的)
发表回复