Java:快速检查int中的数字是否按升序排列

时间:2016-02-18 16:27:51

标签: java

我正在编写一个程序,找到零和Integer.MAX_VALUE之间范围内的所有Armstrong numbers。时间限制是10秒。我发现最耗时的方法是通过只选择那些具有升序数字的数字(如果有的话有尾随零)来缩小要处理的数字范围。在我的机器上运行大约需要57秒。有没有办法让它更快?

static boolean isOK(int x)
{
    int prev = 0;

    while(x > 0)
    {
        int digit = x % 10;
        if((digit > prev || digit == 0) && prev != 0) return false;
        x /= 10;
        prev = digit;
    }
    return true;
}

此方法将要处理的数字从2.147.483.647减少到140.990。

6 个答案:

答案 0 :(得分:1)

另一种方法是逐个构建一组阿姆斯壮的数字并计算它们,而不是检查每个数字,看它是否是阿姆斯壮的数字。

在构建整个集合时,请注意,当您选择每个数字时,您可以为下一个位置选择一组数字,依此类推。实现这种方法的两种替代方法是递归和回溯(这基本上是实现递归的更便宜的方式)。 这种方法不需要使用耗时的除法和余数运算。

答案 1 :(得分:1)

也许不是筛选所有的整数,而是按升序排列数字。我认为你可能想要一组字符串(而不是整数),因为它更容易构建(通过附加/前置字符递归),然后你只需要单独的“数字”进行功率测试。

答案 2 :(得分:0)

你执行两个部门。分割比乘法慢。那么有没有办法将分裂变成乘法?嗯......是的,有。

public static boolean isArmstrongNumber(int n) {
  int prev = 0;
  while (n > 0) {
    int quotient = n / 10;
    int digit = n - (quotient * 10);
    if ((digit > prev || digit == 0) && prev != 0) {
        return false;
    }
    n = quotient;
    prev = digit;
  }
  return true;
}

答案 3 :(得分:0)

这里的代码很少可以优化。您的时间问题可能在其他地方。但是,我想到了一种技术,那就是Memoization

static Set<Integer> oks = new HashSet<>();

static boolean isOK(int x) {
    if (!oks.contains(x)) {
        int prev = 0;

        while (x > 0) {
            int digit = x % 10;
            if ((digit > prev || digit == 0) && prev != 0) {
                return false;
            }
            x /= 10;
            prev = digit;
        }
        // This one is OK.
        oks.add(x);
    }
    return true;
}

此技巧使用Set来记住所有正确的数字,因此您无需检查它们。你也可以保留Set那些失败的东西,以避免再次检查它们,但保留集合中的所有整数可能会破坏某些东西。

答案 4 :(得分:0)

以下代码不处理尾随零,但值得检查它是否在性能方面看起来很有前途。

static boolean isOK(int x) {
    if (x < 10) {
        return true;
    }

    String xs = Integer.toString(x);
    for (int i = 1; i < xs.length(); i++) {
        if (xs.charAt(i) < xs.charAt(i - 1)) {
            return false;
        }
    }
    return true;
}

答案 5 :(得分:0)

以下代码以与原始代码相同的速度运行x4(笔记本电脑上为3秒)并打印140990 in 3 sec. 方法isOK未更改

public class Main {

    public static boolean isOK(int x) {
        int prev = 0;
        while (x > 0) {
            int digit = x % 10;
            if (prev != 0 && (digit > prev || digit == 0)) return false;
            x /= 10;
            prev = digit;
        }
        return true;
    }

    public static void main(String[] args) throws Exception {
        long start = System.currentTimeMillis();

        Set<Integer> candidates = IntStream.range(0, Integer.MAX_VALUE)
                .parallel()
                .filter(n -> isOK(n))
                .boxed()
                .collect(Collectors.toSet());
        long stop = System.currentTimeMillis() - start;

        System.err.printf("%d in %d sec.", candidates.size(), stop / 1000);
    }
}