HDOJ ACM 1017题目一般是求解“数字统计”类问题,常见题目是统计某个数字在1到n范围内出现的次数。

下面给你一个Java版本的思路与代码示例,帮助你理解和实现。


题目描述(常见版本)

统计数字d在从1n的所有整数中出现的总次数。

比如:

  • 输入:n=12, d=1
  • 输出:5 (数字1在1,10,11,12中出现,总共5次)

解决思路

最直接的思路:

  1. 遍历1n的每个数字
  2. 将数字转换为字符串,统计其中字符d出现的次数
  3. 累加计数

这种方法简单但当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开头的)