我已经开始学习用Java编写代码并决定使用Project Euler网站给我一些小任务来尝试完成我学习的每一段新编码。所以我遇到了Problem 3:
13195的主要因素是5,7,13和29。 600851475143的最大主要因素是什么?
我想到了这个问题并研究了许多关于素数的不同理论,以及如何通过各种不同的计算找到它们(以Eratosthenes的筛子为例),我想到的解决方案是测试2 - >的数字。 n并查看它们是否为素数,如果它们是那么我将Tn变量(在本例中为600851475143)除以新发现的素数并查看它是否是一个因子。如果是,我会将它分配给变量Hp(最高素数),在程序结束时我会将Hp输出到控制台以给出我的结果。
这是我的代码:
public class Largest_Prime_Factor_NEW_SOLUTION {
static long Tn = 600851475143L;
static long Hp = 0;
static boolean isPrime = false;
public static void main(String[] args) {
for (long i=2; i<Tn; i++) {
System.out.println("TESTING NUMBER " + i);
for (long k=2; k < i; k++) {
if (i % k == 0) {
System.out.println(i + " IS NOT A PRIME");
break;
} else if (k + 1 == i) {
isPrime = true;
}
}
if (isPrime) {
System.out.println(i + " IS A PRIME");
if (Tn % i == 0) {
System.out.println(Tn + " IS DIVISIBLE BY " + i);
Hp = i;
} else {
System.out.println(Tn + " IS NOT DIVISIBLE BY " + i);
}
}
isPrime = false;
}
System.out.println("THE HIGHEST PRIME NUMBER OF " + Tn + " IS " + Hp);
}
}
现在我知道这段代码非常低效,而且刚开始我已经设法从我开始的地方压缩它(到处都有循环!)但是我要问的是,我该如何改进呢?它惹恼了我,因为我所研究的一切都与其他人的做法相矛盾,而且非常令人困惑。我已经尝试了筛选方法,但我知道布尔数组只能是一个int数组,而不是一个长数组?
据我所知,在开始编码时,我将仅限于可以使用的知识,但只是出于兴趣,我很想知道最终的解决方案是什么。
答案 0 :(得分:7)
你可以做的是找到Tn
的最低除数。假设它是p
,再次找到Tn/p
的最低除数,依此类推。
现在,每一步p
都是素数[下面的解释]。所以收集它们,它们是Tn
的主要除数。
为了更好的时间复杂度,您可以检查最多只有ceil(sqrt(Tn))
的除数,而不是Tn-1
。
当您开始检查Tn
的素数除数时,您可以从2
开始。一旦你得到一个素数除数p
,就不要再从2
开始Tn/p
。因为Tn/p
也是Tn
的除数,因为Tn
的除数不小于p
,Tn/p
也没有。p
。因此,再次从p
开始[Tn
可以在p
]中拥有多个权力。如果Tn
未划分p+1
,请转到{{1}}。
示例:
Tn = 45
1.从2开始.2不分45
2.下一个测试是针对3. 45可以被3整除。所以3是它的主要除数
3.现在检查45/3 = 15的素数除数,但从3开始,而不是从2开始。
好吧,15可以被3整除。所以从15/3 = 5开始
5.注意5,ceil(sqrt(5))是3.但是5不能被3整除。但是因为4>小区(SQRT(5))
我们可以毫无疑问地说5是素数。
因此45的主要除数是3和5。
为什么数字的最小除数(1除外)是素数?
假设上述陈述是错误的。那么数字N具有最小但复合的除数,比如C。
所以C | N.
现在C是复合的,它的除数小于自身但大于1
比如说C的这个除数是P.
所以P | C,但我们有C | N =&gt; P | N,其中1 < P&lt; C.
这与我们的假设相矛盾,即C是N的最小除数,所以一个数的最小除数总是一个素数。
答案 1 :(得分:1)
感谢您的帮助,在阅读完评论和答案之后,我设法将代码进一步压缩到以下内容:
public class Largest_Prime_Factor_NEW_SOLUTION_2 {
static long Tn = 600851475143L;
public static void main(String[] args) {
for (long i = 2; i < Math.sqrt(Tn); i++) {
if(Tn % i == 0) {
Tn = Tn / i;
i--;
}
}
System.out.println(Tn);
}
}
它完美无缺!再次感谢您的帮助和时间来帮助我理解。我知道这更像是一个数学问题,而不是编码问题,但它帮助我理解了一些事情。我现在要去学习别的东西了:))
答案 2 :(得分:0)
有很多方法可以改进这样的程序,但改进主要是用数学而不是编程:
在查找因素时,请检查每个数字,而不仅仅是素数。如果你找到一个因素检查它是否是素数。你可以通过这种方式节省许多素数。
复合数的最大素数因子最多可以是数字的平方根,因此您可以提前停止迭代。
使用快速素性测试而不是进行试验分割http://en.wikipedia.org/wiki/Primality_test
然后,这是一次性的。不要过度复杂化。
答案 3 :(得分:0)
由于您正在将此作为一项学习练习,当您对当前课程进行了充分的改进时,为什么不尝试以不同的方式解决同一问题? Fermat Factorization Method首先找到大的因素。
答案 4 :(得分:0)
通过试验除法对复合数进行分解的简单算法如下:
function factors(n)
f, fs := 2, []
while f * f <= n
while n % f == 0
fs.append(f)
n := n / f
f := f + 1
if n > 1
fs.append(n)
return fs
该算法可以改进,并且有更好的算法来分解大数,但它足以完成您的任务。当您准备好了更多时,我在我的博客中谦虚地推荐essay 使用Prime数字编程,其中包括该算法的实现以及Java中的其他实现。
答案 5 :(得分:0)
这是this的java版本:
static boolean isPrime(int n){
if (n == 2) return true;
if (n == 3) return true;
if (n % 2 == 0) return false;
if (n % 3 == 0) return false;
int i = 5;
int w = 2;
while (i * i <= n) {
if(n % i == 0)
return false;
i += w;
w = 6 - w;
}
return true;
}
正如@Alexandru描述的那样:它是经典O(sqrt(N))算法的变体。它使用了这样一个事实:素数(除了2和3)的形式是6k-1和6k + 1,并且只看这种形式的除数。