Analisando os deslocamentos de zeros 0️⃣

Nos comentários, vocês apresentaram quase todas as formas de resolver o problema que se pode imaginar.

Claro, o padrão clássico para resolver aqui é dois ponteiros.
Aqui está a solução ideal com complexidade O(n) de tempo e O(1) de memória:

def move_zeroes(nums: list[int]) -> None:
insert_pos = 0

for i in range(len(nums)):
if nums[i] != 0:
# Trocamos o elemento não nulo com o zero "à esquerda"
nums[insert_pos], nums[i] = nums[i], nums[insert_pos]
insert_pos += 1


Sem alocações. Sem pop() do meio da lista. Percorremos o array exatamente uma vez. A variável insert_pos sempre aponta para o primeiro zero disponível. Assim que encontramos um número diferente de zero — simplesmente os trocamos graças ao mecanismo embutido de desempacotamento de tuplas em Python.

🐍 Mas não seria interessante sem algo mais engenhoso. Aqui vai um flex em Python em uma linha sem geradores:
nums.sort(key=bool, reverse=True)


Como funciona? bool(0) retorna False, os outros números — True. A ordenação embutida Timsort em Python é estável — ela preserva estritamente a ordem original dos elementos iguais. Todos os True (números) vão para a esquerda, mantendo sua ordem, e todos os False (zeros) vão para a direita.

Sim, formalmente aqui a complexidade é O(n log n), o que é algoritmicamente pior que dois ponteiros. Mas devido ao fato de que o Timsort é escrito em C de tirar o fôlego, em listas reais de pequeno volume este código fisicamente superará loops em Python puro em velocidade de execução.

#algosobes