我正在编写一个Java程序来计算大数的最大素数因子。但是我对程序的复杂性有一个问题,我不知道是什么导致程序永远运行大数字,它适用于小数字。
我进行了如下操作:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
public class Largest_prime_factor {
public static void main(String[] args)
{
//ArrayList primesArray = new ArrayList();
ArrayList factorArray = new ArrayList();
long largest = 1;
long number = 600851475143L ;
long i, j, k;
//the array list factorArray will have all factors of number
for (i = 2; i < number; i++)
{
if( number % i == 0)
{
factorArray.add(i);
}
}
此处,数组列表将包含该数字的所有因子。 所以我只需要获得主要的,为此,我使用了一种检查数字是否为素数的方法,如果它不是素数,我使用以下方法将其从列表中删除:
java.util.ArrayList.remove()
所以代码的下一部分如下:
for (i = 2; i < number; i++)
{
if (!isPrime(i))
{
factorArray.remove(i);
System.out.println(factorArray);
}
}
System.out.println(Collections.max(factorArray));
}
最后一行打印出最大数量的factorArray,这正是我要找的。 p>
public static boolean isPrime(long n)
{
if(n > 2 && (n & 1) == 0)
return false;
for(int i = 3; i * i <= n; i += 2)
if (n % i == 0)
return false;
return true;
}
}
上面的函数是我用来确定数字是否为素数之前从列表中删除它。
这个程序适用于小数字,但是为大数字提供输出需要永远,尽管最后一个函数非常快。 起初,我曾经在第一个循环中检查一个数字是否为素数,但它甚至更慢。
答案 0 :(得分:3)
您正在循环超过600851475143个数字。
long number = 600851475143L ;
for (i = 2; i < number; i++)
即使我们假设每次迭代花费非常短的时间(小到1微秒),它仍然需要几天才能完成循环。
您需要优化您的寻找逻辑,以便该程序运行得更快。
将迭代次数减少到合理数的一种方法是循环直到数字的平方根。
for (i = 2; i < Math.sqrt(number); i++)
或
for (i = 2; i*i < number; i++)
答案 1 :(得分:2)
600851475143L的素因子的计算应该不到一毫秒(算法效率不是很低)。您的代码目前缺少的主要部分:
边框应为sqrt(数字)而不是数字
应该在while循环中检查当前值(以防止将非素因子添加到列表中,减少范围以进行检查)。
最大在找到因子后,应将数值(以及边界)减少到数字/因子。
可以进一步改进,例如仅迭代非偶数(或仅迭代不是2和3的倍数的数字)等。
关于codereview(link)的相同问题的示例实现:
public static long largestPrimeFactor(
final long input) {
////
if (input < 2)
throw new IllegalArgumentException();
long n = input;
long last = 0;
for (; (n & 1) == 0; n >>= 1)
last = 2;
for (; n % 3 == 0; n /= 3)
last = 3;
for (long v = 5, add = 2, border = (long) Math.sqrt(n); v <= border; v += add, add ^= 6)
while (n % v == 0)
border = (long) Math.sqrt(n /= last = v);
return n == 1 ? last : n;
}
答案 2 :(得分:1)
for (i = 2; i < number; i++)
{
if( number % i == 0)
{
factorArray.add(i);
}
}
对于较大的输入尺寸,您将访问该数字的值。删除因子的循环也是如此。
long number = 600851475143L ;
这是一个巨大的数字,你需要两次循环。尝试计算每10,000或100,000(如果i%10000打印(i))并且您将了解它的移动速度。
答案 3 :(得分:1)
其中一种可能的解决方案是仅测试小于大数的素数是否除以它。 所以我检查了
for (i=2; i < number; i++)
{
if(isPrime(i))
{
if( number % i == 0)
{
factorArray.add(i);
}
}
}
所以在这里我只会用素数除以而不是除以所有小于600851475143的数字。 但这仍然不是很快,需要对算法进行彻底修改才能获得最佳算法。
答案 4 :(得分:0)
@Balkrishna Rawool建议是正确的方法。为此,我建议改变迭代,如下所示:for(i = 3; i&lt; Math.sqrt(number); i + = 2)并手动处理2。这将减少你的循环,因为除了2之外的偶数都不是素数。