283. 移动零

283 移动零

题目链接:283. 移动零

image-compressed.png

解题思路

非原地解(Silly Approach)

image-compressed.png

这种方法虽然直观,但由于创建了新数组,不符合题目“必须在原数组上操作”的要求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
if not nums:
return

# 这种方法创建了新数组,不符合原地操作的要求
res = []
for i in nums:
if i != 0:
res.append(i)

for i in range(len(nums) - len(res)):
res.append(0)

# 注意:需要切片赋值 nums[:] = res
# 直接 nums = res 只会改变局部引用,不会影响原始内存地址
nums[:] = res

原地解

方法一:两轮遍历

image-compressed.png

思路:使用两个指针。第一个指针用于记录当前已填充非零元素的位置,第二个指针负责遍历数组。

  1. 第一轮遍历:将所有非零元素按顺序移动到数组前端。
  2. 第二轮遍历:将剩余位置全部补零。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
if not nums:
return

# 慢指针 j 记录下一个非零元素应该存放的位置
j = 0
for i in range(len(nums)):
if nums[i] != 0:
nums[j] = nums[i]
j += 1

# 将剩余位置补零
for i in range(j, len(nums)):
nums[i] = 0

方法二:一轮遍历(快排思想)

image-compressed.png

利用快排(Partition)的思路:以 0 为基准,将非零元素交换到前面。这种方法只需一轮遍历。

1
2
3
4
5
6
7
8
9
10
11
12
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
if not nums:
return

# j 指向处理过的序列的尾部
j = 0
for i in range(len(nums)):
if nums[i] != 0:
# 交换非零元素到前面
nums[j], nums[i] = nums[i], nums[j]
j += 1