[英]Prime Numbers in Java - Algorithms
我已經開始學習使用Java編寫代碼並決定使用Project Euler站點給我一些小任務來嘗試完成我學習的每一段新編碼。 所以我遇到了問題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數組,而不是一個長數組?
我明白,在開始編碼時,我將僅限於可以使用的知識,但只是出於興趣,我很想知道最終的解決方案是什么。
你能做的就是找到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
。
示例:
Tn = 45
1.從2開始.2不分45。
2.下一個測試是針對3. 45可以被3整除。所以3是它的主要除數。
3.現在檢查45/3 = 15的素數除數,但從3開始,而不是從2開始。 4.好吧,15可以被3整除。所以從15/3 = 5開始5.注意5,ceil(sqrt(5))是3.但是5不能被3整除。但是因為4> ceil(sqrt( 5))我們可以毫無疑問地說5是素數。
所以45的主要除數是3和5。
為什么一個數字的最小除數(1除外)是素數?
假設上述陳述是錯誤的。 然后數字N具有最小但復合除數,比如說C.
所以C | N現在C是復合的,它的除數小於自身但大於1。
說這樣的C除數是P.
所以P | C,但我們有C | N => P | N,其中1 <P <C
這與我們的假設相矛盾,即C是N的最小除數,因此數字的最小除數總是素數。
感謝您的所有幫助,在閱讀完評論和答案之后,我設法將代碼進一步壓縮到以下內容:
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);
}
}
它完美無瑕! 再次感謝您的幫助和時間來幫助我理解。 我知道這更像是一個數學問題,而不是編碼問題,但它幫助我理解了一些事情。 我現在要去學習別的東西:)
有很多方法可以改進像這樣的程序,但改進主要是用數學而不是編程:
在尋找因素時,請檢查每個數字,而不僅僅是素數。 如果你找到一個因素檢查它是否是素數。 你會用這種方式省去許多素數檢查。
復合數的最大素數因子最多可以是數字的平方根,因此您可以提前停止迭代。
使用快速素性測試而不是進行試驗分割http://en.wikipedia.org/wiki/Primality_test
再說一遍,這是一次性的。 不要過度復雜化。
既然你正在做這個學習練習,當你對當前的課程進行了充分的改進時,為什么不嘗試以不同的方式解決同樣的問題呢? 費馬分解方法首先找到大因子。
通過試驗分解對復合數進行分解的簡單算法如下:
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
該算法可以改進,並且有更好的算法來分解大數,但它足以完成您的任務。 當你准備好了更多的時候,我在我的博客上謙虛地推薦用Prime數字編寫的論文 ,其中包括該算法的實現和Java中的其他算法。
這是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,並且只看這種形式的除數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.