Whats the best way to find the largest prime factor of a number?
我对编程还不熟悉,我的一个朋友建议我应该在ProjectEuler上做一些练习,以便更好地使用它。我在问题3中遇到了一个问题:
"The prime factors of 13195 are 5, 7, 13 and 29. What is the largest prime factor of the number 600851475143 ?"
号
下面是我的解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | class Program { static void Main(string[] args) { long number = 600851475143; bool prime = true; for (long i = 3; i <= number; i++) { for (long n = 2; n < i; n++) { if (i % n == 0) { prime = false; break; } } if (prime) { if (number % i == 0) { Console.WriteLine(i); } } prime = true; } Console.ReadKey(); } } |
现在,虽然我得到了正确的答案(即6857),但我发现我的方法非常低效。如果你运行我的代码,你会发现它仍然会运行超过2分钟…我的问题是,我如何才能为此编写更高效/更快的代码?
My question is how can I write a more efficient/faster code for this?
号
这是个错误的问题。或者更确切地说,这是一个过早的问题。
正确的问题是:
- 我的程序正确吗?
- 我的计划组织得好吗?
快速编写一个错误的程序可以让你更快地得到错误的答案,这并不是一个改进。要使一个组织不良的程序更快是非常困难的,所以首先要把它组织好。
让我们从对你的程序做一个小小但极其重要的改进开始:我们注意到"这是最重要的吗?"可以由助手清晰地表示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | class Program { static bool IsPrime(long i) { for (long n = 2; n < i; n++) { if (i % n == 0) return false; } return true; } static void Main(string[] args) { long number = 600851475143; for (long i = 3; i <= number; i++) { if (IsPrime(i)) Console.WriteLine(i); } Console.ReadKey(); } } |
看看刚才发生了什么。你的程序突然变得越来越容易理解了。Isprime做什么?它告诉你一个整数是否是素数。主循环做什么?它打印出3和数字之间的所有素数。
现在,重新开始。程序的每个部分都正确吗?不,当给定
既然我们既正确又有条理,我们就可以开始优化了。你能想出办法让我更快吗?当然:
- 我们只需要检查
i 的平方根。(注意,n * n <= i 比n <= Sqrt(i) 快) - 一旦我们检查了2,我们就不需要检查4,6,8,…
你能想出其他方法使它更快吗?
但关键是要组织好你的程序。一旦你有了一个组织良好的程序,你就可以在更高的层次上进行推理,并且你可以找到并消除缓慢的部分。
首先,为了知道一个数是否是素数,您使用的算法效率非常低(顺序(n?2)),可以改进返回数字是否为质数的函数的顺序。
要确定一个数字是否是质数,您需要检查它是否不能被小于n的任何数字整除。
你只需要考虑小于√n的因子,因为如果n可以被某个数字p整除,那么n=p×q,由于p≤q,你可以得出p≤√n。注意,你考虑的是小于n而不是小于√n的因子。
也许这个类似的问题可以帮助你,"下面最大的素数是什么"。
解决这一问题的最佳方法是使用埃拉托斯滕筛。(https://en.wikipedia.org/wiki/screen-of-eratosthenes)
这是一个使用橡皮擦的伪代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | public int primes(int n) { boolean[] isPrime = new boolean[n]; for (int i = 2; i < n; i++) { isPrime[i] = true; } // Loop's ending condition is i * i < n instead of i < sqrt(n) // to avoid repeatedly calling an expensive function sqrt(). for (int i = 2; i * i < n; i++) { if (!isPrime[i]) continue; for (int j = i * i; j < n; j += i) { isPrime[j] = false; } } int count = 0; for (int i = 2; i < n; i++) { if (isPrime[i]) count++; } //return the max prime int maxPrime = 1; for(int i = 0; i < isPrime.count; i++){ if(isPrime[i]){ maxPrime = i; } return maxPrime; } } |
我写了一个方法,可以给你所有的基本因素,其中最大的一个。我的代码正在运行,您可以查看它:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | public void PrimeFactor1(long n) { List<int> sList = new List<int>(); long temp = 1; for (int i = 2; i <= n; i++) { if ((n % i) == 0) { temp = n / i; sList.Add(i); i = 1; n = temp; } } string arr = string.Join(",", sList.ToArray()); Console.Write(arr); Console.WriteLine("."); Console.WriteLine("The Biggest Prime number is: {0}", sList.Max()); } |
号
如果您要处理许多项目Euler问题,那么您需要很好地实现Eratostenes的筛。Eratostenes类的两个有用方法是
ETA:伪代码被修改为不正确。对不起的。