Как реализовать алгоритм подсчёта и сдвига нулей в массиве на Python
Что проверяют
Умеете ли вы решить задачу за один проход и без лишней памяти, а не через remove в цикле. В data-ml к этому почти всегда добавляют вопрос, как сделать то же самое на numpy без питоновского цикла и что будет с NaN.
Как отвечать
Сначала уточните условие: менять список на месте или вернуть новый, сохранять ли порядок ненулевых элементов, что считать результатом подсчёта. Потом каркас на двух указателях:
- указатель записи:
posстоит там, куда ляжет следующий ненулевой элемент. Идёте по списку, ненулевое значение копируете вarr[pos]и сдвигаетеpos; - хвост: после прохода всё от
posдо конца заполняете нулями. Количество нулей получается бесплатно:len(arr) - pos; - вариант с обменом:
arr[pos], arr[i] = arr[i], arr[pos]делает то же за один цикл и не переписывает хвост отдельно; - сложность: время O(n), дополнительная память O(1), порядок ненулевых сохраняется.
Для данных покажите векторный вариант: nz = a[a != 0], затем np.concatenate([nz, np.zeros(a.size - nz.size, dtype=a.dtype)]). Он требует O(n) памяти, зато на больших массивах работает на порядки быстрее цикла. Однострочник sorted(arr, key=lambda x: x == 0) тоже корректен, потому что сортировка в Python стабильная, но это уже O(n log n), и об этом стоит сказать самим.
Проговорите краевые случаи: пустой список, одни нули, ни одного нуля, ноль в самом конце.
Где спотыкаются
Удаляют нули через arr.remove(0) и append(0) прямо в цикле по тому же списку. Итерация сбивается, элементы пропускаются, а каждый remove сам по себе O(n), итого квадрат.
Забывают про типы. В Python False == 0 истинно, поэтому булевы значения тоже уедут в хвост, а -0.0 считается нулём и потеряет знак. NaN нулём не считается и остаётся на месте, в данных это надо оговорить заранее.
Молча меняют входной список и возвращают его же, хотя вызывающий код этого не ждёт. Если функция работает на месте, честнее вернуть None или количество нулей, как это делают list.sort() и random.shuffle().