Дан массив целых чисел
, и требуется переместить все нули в конец массива, сохраняя при этом относительный порядок ненулевых элементов.nums
Для лучшего понимания задачи рассмотрим несколько примеров:
Пример 1:
- Ввод:
= [0, 1, 0, 3, 12]nums
- Вывод: [1, 3, 12, 0, 0]
Пример 2:
- Ввод:
= [0]nums
- Вывод: [0]
Одним из оптимальных способов является использование алгоритма, работающего за линейное время и использующего только один проход по массиву.
Для решения этой задачи мы будем использовать алгоритм с двумя указателями. Один указатель будет указывать на текущий элемент, который мы рассматриваем, а второй будет указывать на место, куда мы должны переместить следующий ненулевой элемент.
- Мы будем двигать правый указатель
от начала массива к его концу.right
- Если элемент, на который указывает правый указатель, не равен нулю, мы будем его обменивать с элементом, на который указывает левый указатель
. После этого мы увеличим левый указатель.left
- После завершения цикла все ненулевые элементы будут находиться в начале массива, а все нули будут в его конце.
def moveZeroes(nums: List[int]) -> None:
left = 0
for right in range(len(nums)):
if nums[right] != 0 and nums[left] == 0:
nums[left], nums[right] = nums[right], nums[left]
if nums[left] != 0:
left += 1
Разберем каждую строку кода из функции
по порядку:moveZeroes
def moveZeroes(nums: List[int]) -> None:
— Это объявление функцииdef moveZeroes(nums: List[int]) -> None:
moveZeroes
, которая принимает список целых чисел
в качестве аргумента и не возвращает ничего (возвращаетnums
). Возвращаемый тип указан в аннотации типов (Python type hints).None
left = 0
— Создается переменнаяleft = 0
, которая будет использоваться как левый указатель для перемещения ненулевых элементов.left
for right in range(len(nums)):
— Это циклfor right in range(len(nums)):
for
, который итерируется по всем индексам элементов списка
.nums
— это правый указатель, который будет использоваться для перебора элементов массива.right
if nums[right] != 0 and nums[left] == 0:
— Это условие проверяет, если элемент массива, на который указывает правый указатель (if nums[right] != 0 and nums[left] == 0:
), не равен нулю и элемент массива, на который указывает левый указатель (nums[right]
), равен нулю.nums[left]
nums[left], nums[right] = nums[right], nums[left]
— Если условие из предыдущего шага выполняется, происходит обмен значениями между элементами массива на позицияхnums[left], nums[right] = nums[right], nums[left]
иleft
. Это позволяет переместить ненулевой элемент на место первого встреченного нуля.right
if nums[left] != 0:
— После того как был выполнен обмен, проверяется элемент на позицииif nums[left] != 0:
. Если он не равен нулю, это означает, что мы уже перенесли ненулевой элемент на его правильное место, иleft
увеличивается наleft
для указания на следующую позицию в массиве.1
left += 1
— Увеличение значенияleft += 1
наleft
для перемещения левого указателя на следующий элемент.1
Этот код обеспечивает перемещение всех нулевых элементов в конец массива, при этом сохраняя порядок ненулевых элементов.
Сложность алгоритма
Временная сложность данного алгоритма составляет [math]O(n)[/math], где [math]n[/math] — количество элементов в массиве. Мы проходим по массиву только один раз.