[英]I need an optimal algorithm to find the largest divisor of a number N. Preferably in C++ or C#
我目前正在使用以下代碼,但對於大量數字非常慢
static int divisor(int number)
{
int i;
for (i = number / 2; i >= 1; i--)
{
if (number % i == 0)
{
break;
}
}
return i;
}
首先認為您可以找到最小的除數 d(當然不等於 1),然后 N/d 將是您正在尋找的最大除數。
例如,如果 N 可被 3 整除,那么您需要 2 次迭代才能找到答案 - 在您的情況下,它大約是 N/6 次迭代。
編輯:為了進一步改進您的算法,您可以僅迭代奇數(在檢查您的數字是否為偶數之后),或者更好的是,如果您預先計算了素數列表,那么您只能迭代它們,因為最小的除數顯然是是素數。
不知道這是否是最佳解決方案,但您最好從 2 開始然后向上,例如:
static int divisor(int number)
{
int i;
for (i = 2; i <sqrt(number); i++)
{
if (number % i == 0)
{
break;
}
}
return number/i;
}
讓它也與素數一起工作:
static int divisor(int number)
{
int i;
for (i = 2; i <=sqrt(number); i++)
{
if (number % i == 0)
{
return number/i;
}
}
return 1;
}
為了限制您的搜索空間,您應該從 2 開始,直到數字的平方根。 可被 2 整除的數字(在有限的搜索空間中)比被 27 整除的數字要多得多,因此從統計上講,您更有可能得到低除數而不是高除數。
當您處理(例如)1,000,000 時,您會發現使用平方根時會有很大的不同,而不是值的一半。 您的方法的 500,000 搜索空間和平方根方法的 1,000 搜索空間之間的差異相當大。
另一個優點是通過對 2 的倍數進行折扣將前面的搜索空間減半。 然后,當你有最低的除數時,最高的就是除以那個數。
偽代碼:
if n % 2 == 0: # Halve search space straight up.
print n / 2
else:
i = 3 # Start at 3.
while i * i <= n: # Or use i <= sqrt(n), provided sqrt is calc'ed once
if n % i == 0:
print n / i # If multiple, get opposite number, print and stop
break
i = i + 2 # Only need to process odd numbers
一個巨大的優化(不確定它是否完全優化 - 你必須向數學家詢問)是僅使用素數向上搜索。 正如 Vladimir 和 Bunnit 所說,最好向上搜索,因為你會發現它要快得多。 然后,返回倒數( number / i
)。 但是,如果您已經嘗試了 2 並且沒有結果,那么嘗試 4 或 6 沒有任何意義。同樣,如果您已經嘗試了 3,那么嘗試 6 或 9 也沒有任何意義。
因此,如果運行時間是一個大問題,您可以在程序中硬編碼前 100 個素數的列表。 測試它們中的每一個。 如果到那時你還沒有找到答案,那么你可以增加 2(跳過偶數)。
尋找大數因子的行業標准方法之一是二次篩算法。
請閱讀以下內容:
http://en.wikipedia.org/wiki/Quadratic_sieve
PS你還應該考慮你的數字有多大。 不同的因式分解算法往往在特定規模下表現良好,而對其他規模則不然。 正如 QS wiki 文章中所指出的,這種方法對於小於大約 100 位十進制數字的數字通常是最快的。
優化:奇數不能有偶數作為最大除數。 盡早在數字上使用此過濾器。 所以如果給出奇數。
先用 2 做除法。
然后每次在循環中將 i 減 2
這將提高奇數的速度。
您基本上遇到了“大數分解”問題,這是當今公鑰加密的基礎,並且已知(或希望)是一個計算難題。 我確實希望你不會找到更好的解決方案,否則整個世界的安全基礎設施都會崩潰...... :)
看看這里: - http://programmingpraxis.com/contents/themes/#Prime%20Numbers
編程Praxis定期為人們設定編程挑戰,以便在周五午餐時間獲得一些樂趣。 這個特殊的問題出現了很多,並且有幾個眾所周知的算法用於解決它用代碼說明。
一些額外的優化:
1. If even then divisable by 2.
2. If the sum of the digits is divisable by 3, then number is divisble by 3 (ie 78 = 7 + 8 = 15 = 1 + 5 = 6 which is divisable by 3)
3. If it ends in 0 or 5 it is divisable by 5
戈登。
最好的算法將取決於你的數字到底有多大。
這個問題基本上和分解整數一樣難——如果有一些分解算法,用它來構造最大的非平凡除數會很容易。 同樣,您對一個數字采用的所有已知因式分解算法中的哪一種應該取決於它的“巨大”,因為對於不同的規模,這些花哨的算法可能具有不同的性能。
您可能會在有關密碼學、算法和計算數論的好書中找到幾個(可能不同的)問題的答案。
同樣,根據您的規模,甚至可以選擇簡單地預先計算一個大列表的質數,保存它,然后在此列表中輸入數字搜索最小的除數 - 這將立即彈出最大的除數, 也。
如果您知道最小除數,則解決方案是應用以下公式:
largest_d = N - N % smallest_d
其中N
是您要查找的最大除數的數字。
def largest_divisor(N, smallest_divisor):
return N - N % smallest_divisor
這段帶有隨機大數 ( N = 94e15
) 和隨機大除數 ( divisor = 21e3
) 的代碼在0.000740051269531 s
完成了在 Python 中的程序運行。
希望這可以幫助。
解決方案的Java實現:
static int highestDivisor(int n) {
if ((n & 1) == 0)
return n / 2;
int i = 3;
while (i * i <= n) {
if (n % i == 0) {
return n / i;
}
i = i + 2;
}
return 1;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.