Доработка программы по поиску ближайшего нуля

Прохожу курсы по Python. Пишу программу по поиску ближайшего нуля.

Если кратко, то есть набор чисел: 4, 5, 0, 3, 2, 0, а должно на выходе быть 2, 1, 0, 1, 1, 0

Преподаватель порекомендовал для улучшения кода использовать некую "векторизацию циклов". Как рассчитать через эту векторизацию до первого нуля и от последнего я сделал, а вот как мне правильно (и по питоновски), сделать расчёт между нулями сделать не могу. Сделал кое как расчёт между нулями в правую сторону, но как рассчитать влево + как это все объединить? Ну и наверное min надо применить, но как?

def distance_counter(land_numbers):
    zeros_numbers = [k for k, v in enumerate(land_numbers) if v == '0']
    distances = [None] * len(land_numbers)

    first = zeros_numbers[0]
    last = zeros_numbers[-1]

    # тут я застрял
    for left, right in zip(zeros_numbers[:-1], zeros_numbers[1:]):
        distances[left:] = [home - left for home in range(left, right)]
        

    # считаем до первого 0
    distances[:zeros_numbers[0]] = [first - home for home in range(zeros_numbers[0])]
    # считаем от последнего 0
    distances[zeros_numbers[-1]:] = [home - last for home in range(zeros_numbers[-1], len(land_numbers))]

    return distances


if __name__ == '__main__':
    #input()
    numbers = '1 0 1 4 0 4 4 5 0 5 4 5'
    land_numbers = numbers.split()
    print(*distance_counter(land_numbers))

Думал сделать как-то так:

for left, right in zip(zeros_numbers[:-1], zeros_numbers[1:]):
    distances[left:right:] = min([home - left for home in range(left, right)], [right - home for home in range(left, right)])

Но так минимальные значения не высчитываются. Да и выглядит как то криво все это (

Данная конструкция

for left, right in zip(zeros_numbers[:-1], zeros_numbers[1:]):    
    distances[left:right] = zip([right - home for home in range(left, right)], [home - left for home in range(left, right)])

возвращает

1 (3, 0) (2, 1) (1, 2) (4, 0) (3, 1) (2, 2) (1, 3) 0 1 2 3

вроде бы остается только выбрать минимальные, но min что-то не пашет (

В общем, сделал вот так:

distances[left:] = map(min, zip([right - home for home in range(left, right)], [home - left for home in range(left, right)]))

так работает, но тесты валятся по времени (те решение занимает много времени и не подходит)


Ответы (1 шт):

Автор решения: GrAnd

Не вижу ничего сложного. Генерируем возрастающий список на половину расстояния от 'left' до 'right' и вставляем его правее 'left'. Потом его переворачиваем и вставляем левее 'right'.

def distance_counter(land_numbers):
    zeros_numbers = [k for k, v in enumerate(land_numbers) if v == '0']
    distances = [0] * len(land_numbers)

    # тут кто-то застрял
    for left, right in zip(zeros_numbers, zeros_numbers[1:]):
        fill = range(1, (right - left) // 2 + 1)
        distances[left+1:left+1+len(fill)] = fill
        distances[right-len(fill):right] = fill[::-1]

    # считаем до первого 0
    distances[:zeros_numbers[0]] = range(zeros_numbers[0], 0, -1)
    # считаем от последнего 0
    distances[zeros_numbers[-1]:] = range(len(land_numbers) - zeros_numbers[-1])

    return distances
→ Ссылка