В моем подходе я выбираю произвольный адрес в целевом массиве, и если он свободен, я добавляю его в список вывода, но если это не так, я сопоставляю этот адрес с адресом, который содержит None
, ближайший к концу списка. Все записи в массиве, находящиеся за его пределами и включающие этот сопоставленный свободный адрес, удаляются из этого списка, поскольку они либо не пустые, либо уже представлены в другом месте списка. Я повторяю этот процесс, отбирая размер целевого списка, облегчая и облегчая поиск новых пустых адресов по мере продвижения. Есть несколько других мелких деталей, которые заставят все это работать, но я думаю, что приведенный ниже код может объяснить это лучше, чем я, словами.
from random import random
def randint(max_val):
return int(random() * max_val)
def assign(values, target):
output = []
mapping = dict()
mmax = 0
size = len(target)
for val in values:
idx = randint(size)
while target[idx] != None:
if idx in mapping:
idx = mapping.pop(idx)
mmax = max(mapping or [0])
break
min_size = max(idx, mmax)
try:
size -= target[size-1:min_size:-1].index(None)
except:
size = min_size + 1
if target[size-1] == None:
size -= 1
mapping[idx] = size
if idx > mmax:
mmax = idx
elif size-1 in mapping:
size -= 1
mapping[idx] = mapping.pop(size)
mmax = max(mapping or [0])
idx = randint(size)
target[idx] = val
output.append(idx)
return output
Обратите внимание, что это изменяет переданный ему список целей. Если вы не хотите изменять его, у вас действительно есть два варианта: реализовать немного дополнительной логики, чтобы проверить, не занят ли уже «свободный» адрес, или скопировать весь список (в этом случае отменить его и исправить индексы). , так что .index()
может работать со списком напрямую, что в любом случае является основным фактором сокращения времени.
Я бы также рекомендовал проверить, что решения, которые он производит, действительны. Я провел некоторое тестирование с моей стороны, но я вполне мог что-то пропустить.