我正在编写一个程序,找到零和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。
答案 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);
}
}