[英]Returning String of prime factors in Java
我知道這是一個經典問題。 我用Java解決了它。 我的解決方案如下。 但是,當我在codefights.com中使用此解決方案時,它超出了執行時間限制。 如果有人能以任何可能的方式向我提出改進此代碼的建議,我將不勝感激。 請隨意批評我的代碼,以便我可以提高我的編碼技能。 謝謝
你被賦予了數字n。
返回n作為其主要因素的產物。
例
對於n = 22,輸出應為“2 * 11”。
對於n = 120,輸出應為“2 * 2 * 2 * 3 * 5”。
對於n = 17194016,輸出應為“2 * 2 * 2 * 2 * 2 * 7 * 59 * 1301”。
[輸入]整數n
小於109的整數。[輸出]字符串
由*符號分割的n的素數因子。 主要因素應該是遞增的順序。
解決方案(JAVA):
public String primefactors(int n) {
String factors = "";
for (int i = 2; i <= n / 2; i++) {
if (isPrime(i)) {
while (n % i == 0) {
n /= i;
if (isPrime(n) && n != 1) {
factors = factors + Integer.valueOf(i).toString() + "*"
+ Integer.valueOf(n).toString();
break;
} else if (n == 1)
factors = factors + Integer.valueOf(i).toString();
else
factors = factors + Integer.valueOf(i).toString() + "*";
}
}
}
return factors;
}
public boolean isPrime(int n) {
boolean prime = true;
if (n == 1)
return false;
else if (n % 2 == 0 && n!=2)
return false;
else if (n % 3 == 0 && n!=3)
return false;
else {
for (int j = 2; j < n / 2; j++) {
if (n % j == 0) {
return false;
}
}
}
return prime;
}
由於n
小於固定數(109),只需使用包含所有prims <= 109的表,而不是動態生成它們。 或至少首先使用erathostenes或atkin的篩子產生prims。 硬編碼表會更好,但使用篩子動態生成表格也會加快速度。 您實現的isPrime()
函數是性能殺手。
函數primefactors
isPrime()
在primefactors
被調用太多次。 例如, i == 2
並且n
有許多除數2
。 熱門電話(isPrime(i))
很好。 但是,在循環內部while (n % i == 0)
,在每次除以n /= 2;
之后檢查isPrime(n)
n /= 2;
。 因此,如果初始n
為100
則函數isPrime()
被調用50
,而下一個循環被調用25
。 這沒有任何意義。 我認為這是最大的問題,因為即使isPrime
在線性時間內工作,在內部循環中多次調用它也是太多了。
在兩種情況下可以從i
的循環中退出: n
在除法之后等於1
,或者如果i
大於sqrt(n)
則n
肯定是素數。
public String primefactors(int n) {
String factors = "";
int max_divisor = sqrt(n);
for (int i = 2; i <= max_divisor; i++) {
if (isPrime(i)) {
while (n % i == 0) {
n /= i;
if (n == 1)
factors = factors + Integer.valueOf(i).toString();
else
factors = factors + Integer.valueOf(i).toString() + "*";
}
max_divisor = sqrt(n);
}
}
// check for the last prime divisor
if (n != 1)
factors = factors + Integer.valueOf(n).toString();
return factors;
}
即便之后改善(和sqrt(n)
作為最大極限isPrime()
你的算法將有線性復雜度O(n)
因為有最多sqrt(n)
循環對i
和探針黃金的最大數量in isPrime
也是sqrt(n)
。
是的,通過為isPrime()
選擇更好的算法可以做得更好。 即使您不允許使用硬編碼的素數表,也可以在運行時生成這樣的查找表(如果有足夠的內存)。 因此,可以使用按升序組織的自動生成的素數列表來探測最大為sqrt(n
)的給定數量。 如果i
變得大於sqrt(n)
則意味着找到下一個素數並且它應該被附加到查找表中並且isPrime()
應該返回true
。
例
假設isPrime
被調用為113
。 在那一刻,查找表有一個以前的素數列表: 2,3,5,7,11,13...
因此,我們嘗試將113
從該列表中的項目除以sqrt(113)
( while (i <= 10)
)。 在嘗試2,3,5,7
之后,列表11
上的下一個項目太大,因此將113
添加到素數列表中,並且函數返回true
。
在最壞的情況下,其他算法可以提供更好的性能。 例如,Eratosthenes篩或Atkin篩可用於有效預先計算的素數列表,直到給定n
具有最佳O(n)
復雜度以實現最佳實施。 在這里,你需要找到所有素數到sqrt(n)
,所以需要O(sqrt(n))
來生成這樣的列表。 生成這樣的列表后,您需要嘗試按數字划分輸入是最多需要sqrt(n)
探測的列表。 因此,算法復雜度為O(sqrt(n))
。 但是,假設你輸入1024
是2
到的功率10
。 在這種情況下,第一個算法會更好,因為它不會去大於2
素數。
你真的需要函數isPrime()嗎?
靈活思考如果我們仔細觀察,您似乎不必在某個范圍內搜索所有素數。 您只需要找到一個給定整數的所有素數除數。 但是,如果我們嘗試將n
除以范圍內的所有整數除以sqrt(n)
,這也是很好的解決方案。 即使這樣的整數不是素數,它也會因條件n % i == 0
而被跳過,因為所有低於被測整數的質數都已從n
刪除,因此簡單的模塊化除法與isPrime()
相同。 O(sqrt(n))
復雜度的完整解決方案:
public String primefactors(int n) {
String factors = "";
int max_divisor = sqrt(n);
for (int i = 2; i <= max_divisor; i++) {
while (n % i == 0) {
n /= i;
max_divisor = sqrt(n);
if (n == 1)
factors = factors + Integer.valueOf(i).toString();
else
factors = factors + Integer.valueOf(i).toString() + "*";
}
}
// check for the last prime divisor
if (n != 1)
factors = factors + Integer.valueOf(n).toString();
return factors;
}
也可以拆分函數以避免if (n == 1)
檢查內循環,但是它不會改變算法的復雜性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.