前言
本篇统一采用如下数组,并且采用双指针。蓝色指针为 l l l,橙色指针为 r r r。初始 l , r l,r l,r 的 index 均为 0。
代码均为 Java。
解法一
记元素向左的偏移量为 offset,初始 offset = 0。
每次发现元素为 0 时增加偏移量,发现元素非 0 且偏移量非 0 时偏移元素。
class Solution {
public void moveZeroes(int[] nums) {
int offset = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 0) {
offset++;
} else if (offset != 0) {
nums[i - offset] = nums[i];
nums[i] = 0;
}
}
}
}
解法二
如下所示,我们可以将
l
l
l 移动到自身右侧第一个元素为 0 的位置,将
r
r
r 移动到
l
l
l 右侧第一个元素非 0 的位置,然后交换元素。
然后再执行上一步骤,循环下去,直至
r
r
r 抵达边界。
class Solution {
public void moveZeroes(int[] nums) {
int l = 0;
int r = 0;
while (r < nums.length) {
if (r == l || nums[r] == 0) {
r++; // 优先检测 r,确保 r 在 l 右侧
} else if (nums[l] != 0) {
l++;
} else {
nums[l] = nums[r];
nums[r] = 0;
}
}
}
}
解法三
出发点是记录第一个元素为 0 的位置,并在每次交换元素时更新。
class Solution {
public void moveZeroes(int[] nums) {
int l = 0;
for (int r = 0; r < nums.length; r++) {
if (nums[r] == 0) continue;
int temp = nums[l];
nums[l] = nums[r];
nums[r] = temp;
l++;
}
}
}
取示例数组如下所示,分析代码的运行过程。
初始时
N
u
m
s
[
l
]
=
N
u
m
s
[
r
]
≠
0
Nums[l] = Nums[r] \neq 0
Nums[l]=Nums[r]=0,交换不产生影响。
l
,
r
l, r
l,r 同步前进。
如下所示,在发现元素 0 时, l l l 保持不变, r r r 前进至 N u m s [ r ] ≠ 0 Nums[r] \neq 0 Nums[r]=0。
再如下所示,交换元素,
l
l
l 前进。
此后 r r r 前进,一直寻找非 0 元素与 l l l 处的 0 交换即可。
复杂度
以上解法复杂度一致。
时间:
Θ
(
n
)
\Theta(n)
Θ(n)
空间:
Θ
(
1
)
\Theta(1)
Θ(1)
推广
这里有附个人题解的双指针题单。
笔者著有 Leetbooks 《图论入门》,《图论进阶》,且在陆续写其他 Leetbooks。致力于提升广大读者真正的算法水平,并兼顾不同阶段的读者,如本科阶段、硕士阶段、职场面试、算法竞赛。