Ось відповідь, яка працює з постійною пам'яттю за рахунок процесора. Це не є гарною відповіддю в контексті оригінального питання (тобто відповіді під час інтерв'ю). Але якщо співбесіда триває 24 години, то це не так вже й погано. ;)
Ідея полягає в тому, що якщо я маю n, що є правильною відповіддю, то наступний у послідовності буде n разів меншим за потужність у два, поділене на деяку потужність 5. Або ж n разів більше потужність 5, поділене на a потужність двох. За умови, що вона ділиться рівномірно. (... або дільник може бути 1;); у цьому випадку ви просто множите на 2 або 5)
Наприклад, перейти від 625 до 640, помножити на 5 ** 4/2 ** 7. Або, загалом, помножити на деяке значення 2 ** m * 5 ** nна деякий m, n, де одне додатне, а одне - негативне або нульове, і множник ділить число рівномірно.
Тепер, хитра частина - знайти множник. Але ми знаємо: а) дільник повинен ділити число рівномірно; б) множник повинен бути більшим одиниці (числа постійно збільшуються), і в) якщо ми виберемо найменший множник, більший за 1 (тобто 1 <f <всі інші f ), то гарантовано це буде наш наступний крок. Крок після цього буде найнижчим кроком.
Неприємна частина - знаходження значення m, n. Є лише можливості журналу (n), тому що відмовитись лише стільки 2-х або 5-х, але мені довелося додати коефіцієнт -1 до +1, як неохайний спосіб вирішити питання про округлення. Отже, нам залишається лише повторити через O (log (n)) кожен крок. Таким чином, це O (n log (n)) загалом.
Хороша новина полягає в тому, що вона приймає значення і знаходить наступне значення, ви можете почати будь-де в послідовності. Отже, якщо ви хочете, щоб наступний був після 1 мільярда, ви можете просто знайти його, повторивши через 2/5 або 5/2 і вибравши найменший множник, більший за 1.
(пітон)
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
Я підтвердив перші 10 000 чисел, які це генерує, проти перших 10 000, створених рішенням відсортованого списку, і це працює принаймні так далеко.
До речі, наступний після трильйона здається 1024 000 000 000.
...
Гм. Я можу отримати продуктивність O (n) - O (1) на значення (!) - та O (log n) використання пам'яті, розглядаючи best()як таблицю пошуку, яку я збільшую поступово. Зараз він економить пам'ять, повторюючи кожен раз, але робить багато зайвих обчислень. Тримаючи ці проміжні значення - і список мінімальних значень - я можу уникнути дублюючої роботи та значно прискорити її. Однак список проміжних значень буде рости з n, отже, пам'яттю O (log n).