Вот ответ, который работает с постоянной памятью, за счет процессора. Это не очень хороший ответ в контексте исходного вопроса (т.е. ответ во время интервью). Но если интервью длится 24 часа, то это не так уж плохо. ;)
Идея состоит в том, что если у меня есть n, который является действительным ответом, то следующий в последовательности будет n умножить на некоторую степень двух, деленную на некоторую степень 5. Или иначе n раз степень 5, деленную на сила двух. При условии, что он делится равномерно. (... или делитель может быть 1;) в этом случае вы просто умножаете на 2 или 5)
Например, чтобы перейти от 625 к 640, умножьте на 5 ** 4/2 ** 7. Или, в более общем случае, умножьте на некоторое значение 2 ** m * 5 ** n
для некоторого m, n, где один положительный, а другой отрицательный или ноль, и множитель делит число равномерно.
Теперь самое сложное - найти множитель. Но мы знаем, что а) делитель должен делить число равномерно, б) множитель должен быть больше единицы (числа продолжают расти), и в) если мы выберем наименьший множитель больше 1 (то есть 1 <f <все остальные f ), то это будет нашим следующим шагом. Шаг после этого будет самым низким шагом.
Неприятная часть находит значение m, n. Есть только log (n) возможности, потому что есть только 2 или 5, которые нужно сдать, но мне пришлось добавить коэффициент от -1 до +1, как неаккуратный способ борьбы с округлением. Таким образом, нам нужно только пройти через O (log (n)) каждый шаг. Так что это O (n log (n)) в целом.
Хорошей новостью является то, что, поскольку оно принимает значение и находит следующее значение, вы можете начать в любом месте последовательности. Поэтому, если вам нужен следующий после 1 миллиарда, он может просто найти его, перебирая 2/5 или 5/2 и выбирая наименьший множитель больше 1.
(Python)
MAX = 30
F = - math.log(2) / math.log(5)
def val(i, j):
return 2 ** i * 5 ** j
def best(i, j):
f = 100
m = 0
n = 0
max_i = (int)(math.log(val(i, j)) / math.log(2) + 1) if i + j else 1
#print((val(i, j), max_i, x))
for mm in range(-i, max_i + 1):
for rr in {-1, 0, 1}:
nn = (int)(mm * F + rr)
if nn < -j: continue
ff = val(mm, nn)
#print(' ' + str((ff, mm, nn, rr)))
if ff > 1 and ff < f:
f = ff
m = mm
n = nn
return m, n
def detSeq():
i = 0
j = 0
got = [val(i, j)]
while len(got) < MAX:
m, n = best(i, j)
i += m
j += n
got.append(val(i, j))
#print('* ' + str((val(i, j), m, n)))
#print('- ' + str((v, i, j)))
return got
Я проверил первые 10000 чисел, которые это генерирует, против первых 10000, сгенерированных решением с отсортированным списком, и это работает, по крайней мере, так далеко.
Кстати, следующий после триллиона, кажется, 1 024 000 000 000.
...
Гектометр Я могу получить производительность O (n) - O (1) на значение (!) - и использование памяти O (log n), рассматривая best()
как справочную таблицу, которую я постепенно расширяю. Прямо сейчас он экономит память путем итерации каждый раз, но выполняет много избыточных вычислений. Держа эти промежуточные значения - и список минимальных значений - я могу избежать дублирования работы и значительно ускорить ее. Тем не менее, список промежуточных значений будет расти с ростом n, следовательно, O (log n) памяти.