我知道这是一个经典问题。我用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的整数。[output] string
由*符号分割的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;
}
答案 0 :(得分:2)
由于n
小于固定数字(109),只需使用包含所有prims&lt; = 109的表,而不是动态生成它们。或至少首先使用erathostenes或atkin的筛子产生prims。硬编码表会更好,但使用筛子动态生成表格也会加快速度。您实施的isPrime()
功能是性能杀手。
答案 1 :(得分:1)
在isPrime()
中调用函数primefactors
太多次了。例如,i == 2
2
中有许多除数n
。热门电话(isPrime(i))
很好。但是,在循环while (n % i == 0)
内,您在每次分割isPrime(n)
后检查n /= 2;
。因此,如果初始n
为100
,则为isPrime()
调用函数50
,并在25
的下一个循环调用函数isPrime
。这没有任何意义。我认为这是最大的问题,因为即使i
在线性时间内工作,在内部循环中多次调用它也是太多了。
在两种情况下可以退出n
的循环:1
在分割后等于n
或i
肯定是sqrt(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
个圈{ {1}} 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)
检查,但是它不会改变算法的复杂性。