Memory Reallocation

Part 1


In [57]:
def reallocate(val, pos, n):
        l = [val // n] * n
        r = val % n
        for i in range(r):
            l[(pos + i + 1) % n] += 1
        return l

def update(b):
    blocks = sorted(list(enumerate(b)), key=lambda v: (v[1], -v[0]), reverse=True)
    pos = blocks[0][0]
    val = blocks[0][1]
    c = [b[i] if i != pos else 0 for i in range(len(b))]
    l = reallocate(val, pos, len(b))
    for i, v in enumerate(c):
        c[i] += l[i]
    return c

def count_until_loop(b):
    count = 0
    previous = set()
    h = hash(tuple(b))
    while h not in previous:
        previous.add(h)
        count += 1
        b = update(b)
        h = hash(tuple(b))
    return count

Test


In [76]:
assert(count_until_loop([0, 2, 7, 0]) == 5)

Solution


In [78]:
input_blocks = [11, 11, 13, 7, 0, 15, 5, 5, 4, 4, 1, 1, 7, 1, 15, 11]
count_until_loop(input_blocks)


Out[78]:
4074

Part 2


In [79]:
def loop_size(b):
    count = 0
    last_seen = {}
    h = hash(tuple(b))
    while h not in last_seen:
        last_seen[h] = count
        count += 1
        b = update(b)
        h = hash(tuple(b))
    return count - last_seen[h]

Test


In [81]:
assert(loop_size([0, 2, 7, 0]) == 4)

Solution


In [82]:
input_blocks = [11, 11, 13, 7, 0, 15, 5, 5, 4, 4, 1, 1, 7, 1, 15, 11]
loop_size(input_blocks)


Out[82]:
2793