【问题标题】:Optimized way to count number of occurrences of a digit in a range of numbers [duplicate]计算数字范围内数字出现次数的优化方法[重复]
【发布时间】:2022-01-22 18:24:24
【问题描述】:

我一直在尝试找到最优化的方法来计算用户为随机个人项目输入的随机数字范围内从 0 到 9 的每个数字的出现次数。 比如说,用户输入 1 作为下限(包括)和 20 作为上限(包括)。输出应该是这样的:

2 12 3 2 2 2 2 2 2 2

用户只能输入正整数。 现在,下面的代码对于小范围的数字/小范围运行良好,但是,正如预期的那样,在我的笔记本电脑上对于大数字/范围需要 4 秒以上。 我一直在努力寻找一种让事情变得更快的方法,我使用模数来获取数字,认为字符串转换可能是罪魁祸首,但它并没有提高速度。我想将运行时间减少到不到 2 秒。一定有办法,但是什么?这是我的原始代码:

import java.util.Scanner;

public class CountDigitsRandomRange {
    public static void main(String[] args) {
        Scanner s = new Scanner(System.in);
        String g = s.nextLine();

        while (!g.equals("0 0")) {
            String[] n = g.split(" ");
            long x = Long.parseLong(n[0]);
            long y = Long.parseLong(n[1]);

            long zero = 0;
            long one = 0;
            long two = 0;
            long three = 0;
            long four = 0;
            long five = 0;
            long six = 0;
            long seven = 0;
            long eight = 0;
            long nine = 0;

            for (long i = x; i <= y; i++) {
                String temp = String.valueOf(i);

                for (int j = 0; j < temp.length(); j++) {
                    if (temp.charAt(j) == '0') {
                        zero++;
                    }
                    if (temp.charAt(j) == '1') {
                        one++;
                    }
                    if (temp.charAt(j) == '2') {
                        two++;
                    }
                    if (temp.charAt(j) == '3') {
                        three++;
                    }
                    if (temp.charAt(j) == '4') {
                        four++;
                    }
                    if (temp.charAt(j) == '5') {
                        five++;
                    }
                    if (temp.charAt(j) == '6') {
                        six++;
                    }
                    if (temp.charAt(j) == '7') {
                        seven++;
                    }
                    if (temp.charAt(j) == '8') {
                        eight++;
                    }
                    if (temp.charAt(j) == '9') {
                        nine++;
                    }
                }
            }
            System.out.println(zero + " " + one + " " + two + " "+three + " " + four
             + " " + five + " " + six + " " + seven + " " + eight + " " + nine);
            g=s.nextLine();
        }
    }
}

我在网上看到了一些与我的问题类似的解决方案,但它们大多是 C/C++,我不明白语法。

【问题讨论】:

  • 为什么要进行昂贵的字符串拆分操作?您可以遍历整个字符串中的每个字符,并使用 switch-case 来增加计数器匹配的数字。这应该是最快的解决方案。
  • @magicmn 不,这还需要一些时间。也许有更好的方法可以通过动态编程来做到这一点,但不知道如何。

标签: java algorithm optimization


【解决方案1】:

这是一个使用模数的简单实现。如果您想要更快的代码,您需要找到一些智能公式,在不执行实际计算的情况下为您提供结果。

import java.util.Arrays;

public class Counter
{
    private static long[] counts = new long[10];

    public static void count(long x, long y)
    {
        Arrays.fill(counts, 0);
        for(long val=x; val<=y; val++)
            count(val);
    }

    public static void count(long val)
    {
        while(val>0)
        {
            int digit = (int)(val % 10);
            counts[digit]++;
            val /= 10;
        }
    }

    public static void main(String[] args)
    {
        count(1, 20);
        System.out.println(Arrays.toString(counts));
    }
}

输出:

[2, 12, 3, 2, 2, 2, 2, 2, 2, 2]

【讨论】:

  • 感谢您的解决方案。你的代码肯定比我的要好得多,但是对于像 100000000 和 100000000 这样的大数字仍然需要很长时间。你是对的,也许它需要一些智能解决方案,而我实际上并不计算任何东西
  • @Sammie:范围越大,计算结果所需的时间就越长。如果范围很大,例如 10,000 或更大,您可以通过打印消息来管理用户期望。当他们阅读并理解该消息时,您的代码将完成其计算。
【解决方案2】:

所以这是一个您可能不知道@Sammie 的问题。在我看来,在提高操作效率方面,您不应该使用运行器在 Java 中提供的秒数来计算时间。据我所知,更客观的计算是使用Java的内部方法,它依赖于CPU时钟来计算时间。这样,不同 PC 之间的差异就会减少(尽管我不相信这会完全消除)。请在下面查看我的参考资料:

  1. Clock milis (only use this if you cannot use the solution below)
  2. Nanoseconds

编辑:这里是another stack overflow post discussing this matter。纳秒似乎更可取。

之后你需要做的就是转换成分钟,你现在应该计算得更精确了。

【讨论】:

  • 你不应该使用任何一个来衡量和比较操作的性能。JVM 需要一些时间来“预热”并且重复这个过程几千次将减少大部分随机性测试可以给。所以最好改用基准测试库。
  • @magicmn 我不知道 Java 的基准测试库。我会看看并可能更新我的答案。感谢您的信息。
  • @NicktheCommunityScientist 嗯,我只是说明了我的用户必须等待多长时间才能看到结果的时间。分钟/秒/纳秒等内部计算时间对他们来说无关紧要。他们想要即时结果,就像我的代码给出的小值/范围一样。像 1000000 和 100000000 这样的大数字不会发生这种情况,这就是我发布此内容的原因,因此有人可以指导我提供更好的版本或告诉我哪里出错了。
  • @Sammie 好的,没关系。我想我误解了这个问题。我会看看能不能帮上忙。
猜你喜欢
  • 1970-01-01
  • 2020-11-09
  • 2015-09-16
  • 2017-03-19
  • 1970-01-01
  • 2015-08-28
  • 2011-08-31
  • 1970-01-01
  • 2018-10-23
相关资源
最近更新 更多