Я раскрываю все скрытые комментарии с правильными решениями к позавчерашней задачке. Если хотите все еще решать ее самостоятельно, не заглядывайте в комментарии. Спасибо всем, кто решал. Первый, кто нашел оптимальное решение за O(N) времени и O(1) памяти -
ilyaraz.
Вот еще одна программистская задачка. Я когда-то знал ее решение и забыл, недавно с удовольствием решил снова. Эта задачка довольно хорошо известна, и в частности часто преподается на курсах продвинутых структур данных, и упоминается в учебниках. Так что многие наверняка ее знают - если вы знаете решение, то не пишите в комментариях. Для тех, кто не знает, это отличное упражнение для ума, по-моему.
Задача: требуется воплотить массив с дефолтным значением для всех элементов, т.е. структуру данных с тремя операциями: get(i), set(i, value) и setdefault(value). Любой вызов get() с индексом, который до сих пор ни разу не передавался set(), должен возвращать последнее выставленное дефолтное значение (или 0, если такого не было). Сложность в том, что все три операции: get, set и setdefault, должны занимать O(1) времени. При этом нельзя рассчитывать на то, что отведенная нам память имеет какой-либо специальный вид, например, заполнена нулями. Любая используемая память изначально содержит случайные байты, которые мы никак не можем контролировать.
Вот еще одна программистская задачка. Я когда-то знал ее решение и забыл, недавно с удовольствием решил снова. Эта задачка довольно хорошо известна, и в частности часто преподается на курсах продвинутых структур данных, и упоминается в учебниках. Так что многие наверняка ее знают - если вы знаете решение, то не пишите в комментариях. Для тех, кто не знает, это отличное упражнение для ума, по-моему.
Задача: требуется воплотить массив с дефолтным значением для всех элементов, т.е. структуру данных с тремя операциями: get(i), set(i, value) и setdefault(value). Любой вызов get() с индексом, который до сих пор ни разу не передавался set(), должен возвращать последнее выставленное дефолтное значение (или 0, если такого не было). Сложность в том, что все три операции: get, set и setdefault, должны занимать O(1) времени. При этом нельзя рассчитывать на то, что отведенная нам память имеет какой-либо специальный вид, например, заполнена нулями. Любая используемая память изначально содержит случайные байты, которые мы никак не можем контролировать.
no subject
Date: 2011-01-07 03:05 pm (UTC)Как раз O(1) для set и get
no subject
Date: 2011-01-07 03:06 pm (UTC)no subject
Date: 2011-01-07 03:18 pm (UTC)no subject
Date: 2011-01-07 03:19 pm (UTC)Если да, то я умею, буквально пару недель назад пришлось изобрести, чтобы не состариться за время инициализации :))
no subject
Date: 2011-01-07 03:22 pm (UTC)Тогда будет жёсткий предел O(1) по времени, но за счёт памяти и операций копирования после некоторых set.
no subject
Date: 2011-01-07 03:25 pm (UTC)для хранения выделяется непрерывный участок виртуальной памяти - обычный массив в С++
плюс дополнительный "индексный" массив uint'ов длины array_length / sizeof(int) / 8 + 1 - т.е. по одному биту на элемент массива.
его придётся заполнить нулями, но эта операция в 32-64 раза быстрее чем заполнение нулями основного массива, которое в данном случае не потребуется
ну а дальше просто - по битовой маске и содержимому индексного массива понимаем были ли там пользовательские данные, и если нет - возвращаем текущее default-значение. Очевидно, set должен взводить бит соответствующей ячейки:
index[ i \ sizeof(int) ] & ( 1 << (i % sizeof(int)) )
no subject
Date: 2011-01-07 03:25 pm (UTC)Вы можете предположить, простоты ради, что максимальный размер массива известен заранее, и подготовить под него вашу структуру данных, но все эти подготовки должны занимать O(1) времени, а не O(n). Т.е. можно например заранее выделить нужную память с помощью malloc(), но нельзя обнулить ее всю в цикле, или что-то еще во все ее ячейки записать.
no subject
Date: 2011-01-07 03:28 pm (UTC)no subject
Date: 2011-01-07 03:29 pm (UTC)no subject
Date: 2011-01-07 03:29 pm (UTC)no subject
Date: 2011-01-07 03:29 pm (UTC)no subject
Date: 2011-01-07 03:35 pm (UTC)get возвращает
entry[1]==sha256(entry[0]) ? entry[0] : default
no subject
Date: 2011-01-07 03:39 pm (UTC)no subject
Date: 2011-01-07 03:39 pm (UTC)Что-то я не догоняю.
Смотрю питоновый код.
берем входящие данные 1123
Идем по коду
def finddup(arr):
i = len(arr) - 1 # last //i=3
looplen = 0
while looplen < n:
i = arr[i] //i = arr[3] = 3
looplen += 1
if arr[i] == i: //3 == 3
# no loop, fixed point
return i //Ответ = 3
А должно быть 1.
Я понимаю, что это я дурак, но не пойму, где именно.
Просто я тоже, когда пытался решить, уперся в циклы, но не смог из них пользы достать со сложностью O(n).
no subject
Date: 2011-01-07 03:41 pm (UTC)no subject
Date: 2011-01-07 03:43 pm (UTC)no subject
Date: 2011-01-07 03:43 pm (UTC)no subject
Date: 2011-01-07 03:44 pm (UTC)Т.е. входящие данные должны быть 0012
no subject
Date: 2011-01-07 03:46 pm (UTC)Хотя крутился вокруг.
Спасибо
no subject
Date: 2011-01-07 03:48 pm (UTC)При вызове setdefault(value) делаем lastDef = value и defCounter++.
При вызове set(i, value) в main[i] записываем value, а в aux[i] -- defCouner.
Смысл aux[i] -- "после aux[i] по счёту вызова setdefault() значение main[i] изменилось"
На вызов get(i) сначала сверям текущий defCounter и aux[i]. Если defCounter > aux[i], возвращаем lastDef (после последнего обновления дефолтного значения main[i] не менялся), если defCounter == aux[i], возвращаем main[i]
no subject
Date: 2011-01-07 03:49 pm (UTC)Или можно наоборот сказать: будем считать индексы массива от 0 до N-1, а значения от 1 до N-1, и тогда начнем цикл с первого значения (индекс 0), потому что к нему невозможно будет вернуться. Тогда начинаем с i=0 и делаем i = arr[i].
no subject
Date: 2011-01-07 03:59 pm (UTC)no subject
Date: 2011-01-07 04:00 pm (UTC)no subject
Date: 2011-01-07 04:18 pm (UTC)no subject
Date: 2011-01-07 04:36 pm (UTC)