Как учесть случаи с нулями в произведении элементов списка?
Что проверяют
Видите ли вы, что ноль ломает не само умножение, а приёмы вокруг него: деление и логарифмы. Чаще всего вопрос звучит как продолжение задачи «произведение всех элементов, кроме текущего», и следом просят решение без деления.
Как отвечать
Сначала уточните, о какой задаче речь.
- произведение всего списка: один ноль делает результат нулём, из цикла можно выйти сразу. В Python есть
math.prod, для пустого списка он возвращает 1: это нейтральный элемент умножения, а не 0; - произведение всех, кроме текущего, через деление: считаете произведение ненулевых и число нулей. Нулей нет: ответ
total // xдля целых. Один ноль: на его позиции стоит произведение остальных, везде ноль. Два и больше: весь ответ из нулей; - то же без деления: префиксные и суффиксные произведения. Первым проходом пишете в
res[i]произведение всех элементов слева, вторым домножаете на произведение всех справа. O(n) по времени, O(1) памяти сверх ответа, нули обрабатываются сами, без веток; - произведение вероятностей: в ML длинное произведение уходит в underflow, поэтому суммируют логарифмы.
np.log(0)даёт-infс предупреждением, так что нули и знак учитывают отдельно, а логарифмируют только модули ненулевых значений.
Для data-ml позиции полезно помнить про NumPy: np.prod на целочисленном массиве переполняется молча, int64 просто перескакивает через границу без ошибки. Если значения большие, приводите к float64 или считайте в логарифмах.
Где спотыкаются
Для случая с одним нулём возвращают произведение ненулевых как ответ для всего списка. Это неверно: произведение списка с нулём всегда ноль, особой ветки заслуживает только задача «кроме текущего».
Делят на элемент без проверки и получают ZeroDivisionError в Python или inf и nan в NumPy, которые тихо растекаются по дальнейшим расчётам.
Для пустого списка отвечают 0 «по ощущению». Интервьюер почти наверняка спросит почему, и правильный ответ здесь 1.