Существует решение, которое бы приняло 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, вы можете сначала выполнить исчерпывающий поиск для a_3=25
с помощью gcd(a_3, a_i)
, чтобы найти реальный максимум 5
, а затем отфильтровать gcd(m/a_i, a_i), i!=3
, которые меньше илиравно 5
(в приведенном выше примере это отфильтровывает все остальные).
Добавлено для пояснения и обоснования :
Чтобы понять, почему это должноработа, обратите внимание, что gcd(a_i, a_j)
делит gcd(m/a_i, a_i)
для всех j!=i
.
Давайте назовем gcd(m/a_i, a_i)
как g_i
, а max(gcd(a_i, a_j),j=1..n, j!=i)
как r_i
.То, что я говорю выше, это g_i=x_i*r_i
, а x_i
- это целое число.Очевидно, что r_i <= g_i
, поэтому в n
операциях gcd мы получаем верхнюю границу для r_i
для всех i
.
Приведенное выше утверждение не очень очевидно.Давайте рассмотрим его немного глубже, чтобы понять, почему это так: gcd a_i
и a_j
является произведением всех основных факторов, которые встречаются как в a_i
, так и a_j
(по определению).Теперь умножьте a_j
на другое число, b
.Значение gcd для a_i
и b*a_j
равно или gcd(a_i, a_j)
, или кратно ему, потому что b*a_j
содержит все простые множители a_j
и еще несколько простых факторов, внесенных b
, чтотакже могут быть включены в факторизацию a_i
.На самом деле, gcd(a_i, b*a_j)=gcd(a_i/gcd(a_i, a_j), b)*gcd(a_i, a_j)
, я думаю.Но я не вижу способа использовать это.:)
В любом случае, в нашей конструкции m/a_i
- это просто ярлык для вычисления произведения всех a_j
, где j=1..1, j!=i
.В результате, gcd(m/a_i, a_i)
содержит все gcd(a_i, a_j)
как фактор.Таким образом, очевидно, что максимум этих отдельных результатов gcd разделит g_i
.
Теперь наибольшее значение g_i
представляет для нас особый интерес: это либо максимум самого gcd (если x_i
1) или хороший кандидат на то, чтобы стать таковым.Для этого мы делаем еще одну n-1
операцию gcd и вычисляем r_i
явно.Затем мы отбрасываем все g_j
меньше или равно r_i
в качестве кандидатов.Если у нас нет другого кандидата, мы закончили.Если нет, мы берем следующую наибольшую g_k
и вычисляем r_k
.Если r_k <= r_i
, мы сбрасываем g_k
и повторяем с другим g_k'
.Если r_k > r_i
, мы отфильтровываем оставшиеся g_j <= r_k
и повторяем.
Я думаю, что возможно построить набор чисел, который заставит этот алгоритм работать в O (n ^ 2) (если мы не сможемотфильтровывать что угодно), но на случайных наборах чисел, я думаю, это быстро избавит от больших кусков кандидатов.