Algorithm 某些数字之间的最大GCD
我们有一些非负数。我们想找到gcd最大的一对。实际上这个最大值比这对更重要! 例如,如果我们有: 2 4 5 15 gcd(2,4)=2 gcd(2,5)=1 gcd(2,15)=1 gcd(4,5)=1 gcd(4,15)=1 gcd(5,15)=5Algorithm 某些数字之间的最大GCD,algorithm,math,algebra,number-theory,Algorithm,Math,Algebra,Number Theory,我们有一些非负数。我们想找到gcd最大的一对。实际上这个最大值比这对更重要! 例如,如果我们有: 2 4 5 15 gcd(2,4)=2 gcd(2,5)=1 gcd(2,15)=1 gcd(4,5)=1 gcd(4,15)=1 gcd(5,15)=5 答案是5。您可以使用欧几里德算法来找到两个数字的GCD while (b != 0) { int m = a % b; a = b; b = m; } return a; 伪码 function getGcdMax(a
答案是5。您可以使用欧几里德算法来找到两个数字的GCD
while (b != 0)
{
int m = a % b;
a = b;
b = m;
}
return a;
伪码
function getGcdMax(array[])
arrayUB=upperbound(array)
if (arrayUB<1)
error
pointerA=0
pointerB=1
gcdMax=0
do
gcdMax=MAX(gcdMax,gcd(array[pointera],array[pointerb]))
pointerB++
if (pointerB>arrayUB)
pointerA++
pointerB=pointerA+1
until (pointerB>arrayUB)
return gcdMax
函数getGcdMax(数组[])
arrayUB=上限(数组)
如果(arrayUBarrayUB)
波因特拉++
pointerB=pointerA+1
直到(指针B>arrayUB)
返回gcdMax
我能想到的优化是 1) 从两个最大的数字开始,因为它们可能具有最多的基本因子,因此可能具有最多的共享基本因子(因此GCD最高) 2) 当计算其他对的GCD时,如果低于当前最大GCD,可以停止欧几里德算法循环 在我的脑海中,我想不出一种方法,你可以计算出一对中最好的GCD,而不试着单独计算出每一对(并像上面一样优化一点) 免责声明:我以前从未考虑过这个问题,上面的问题我都不知道。也许有更好的办法,但我可能错了。如果有人愿意,我很乐意更详细地讨论我的想法。:) 一般来说,这个问题没有
O(n log n)
解决方案。事实上,最坏的情况是列表中项目的数量O(n^2)
。考虑下面的一组数字:
2^20 3^13 5^9 7^2*11^4 7^4*11^3
只有最后两个的GCD大于1,但通过查看GCD知道这一点的唯一方法是尝试每一对,并注意其中一对大于1
因此,你被无聊的蛮力困住了,尝试每一对方法,也许有一些聪明的优化,以避免在你已经找到一个大的GCD时做不必要的工作(同时确保你不会错过任何东西)。如果你想要一个明显算法的替代方案,那么假设你的数字在一个有界的范围内,如果你有足够的内存,你可以比O(N^2)时间快,N是数值的数量:
- 创建一个小整数类型的数组,索引1到最大输入。O(1)
- 对于每个值,增加索引中每个元素的计数,该计数是数字的一个因子(确保不进行换行)。O(N)
- 从数组末尾开始,向后扫描,直到找到大于等于2的值。O(1)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
4 2 1 1 2 0 0 0 0 0 0 0 0 0 1
我不知道对于你必须处理的输入来说,这是否真的更快。涉及的常量因素很大:值的边界以及在该边界内分解值的时间
您不必对每个值进行因式分解-您可以使用备忘录和/或预生成的素数列表。这让我想到,如果你在记忆因子分解,你不需要数组:
- 创建一个int的空集,以及迄今为止的最佳值1
- 对于每个输入整数:
- 如果低于或等于目前为止的最佳值,请继续
- 检查它是否在集合中。如果是,则至今最佳=最大值(至今最佳,此值),继续。如果没有:
- 将其添加到集合中
- 对其所有因子重复此操作(大于目前为止的最佳值)
完全分解每个数字,将其存储为素数指数序列(例如2为{1},4为{2},5为{0,0,1},15为{0,1,1})。然后,你可以计算gcd(a,b),方法是取每个指数的最小值,再乘以它们。不知道这是否比欧几里得平均速度快,但它可能是。显然,它会占用更多内存。有一种解决方案需要O(n): 让我们的数字是
a_i
。首先,计算m=a_0*a_1*a_2*…
。对于每个数字a_i,计算gcd(m/a_i,a_i)
。您要查找的数字是这些值中的最大值
我没有证明这总是正确的,但在你的例子中,它是有效的:
m=2*4*5*15=600,
max(gcd(m/2,2)、gcd(m/4,4)、gcd(m/5,5)、gcd(m/15,15))=max(2,2,5,5)=5
注意:这是不正确的。如果数字
a_i
有一个因子p_j
重复了两次,并且如果另外两个数字也包含这个因子p_j
,则得到的结果不正确p_j^2
而不是p_j
。例如,对于集合3,5,15,25
,您得到的答案是25
,而不是5
但是,您仍然可以使用它快速过滤出数字。例如,在上述情况下,一旦确定25,您可以首先使用gcd(a_3,a_i)
对a_3=25
进行彻底搜索,以找到真正的最大值,5
,然后过滤掉gcd(m/a_i,a_i),i=小于或等于5
的3
(在上面的示例中,这会过滤掉所有其他)
增加
max_gcd = 1
# assuming you want pairs of distinct elements.
sort(a) # assume in place
for ii = n - 1: -1 : 0 do
if a[ii] <= max_gcd
break
for jj = ii - 1 : -1 :0 do
if a[jj] <= max_gcd
break
current_gcd = GCD(a[ii], a[jj])
if current_gcd > max_gcd:
max_gcd = current_gcd