题目
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
提示:
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
进阶:你能尽量减少完成的操作次数吗?
解法
解法一
- pre指针向前推进,每遇到一个0,就将创建指针指向后面的数,让后面的元素都向前推,最后将长度-1;
- 给数组末尾补零至原本的长度。
class Solution {
public void moveZeroes(int[] nums) {
if (nums.length == 1 && nums[0] == 0) return;
int length = nums.length;
int pre = 0;
for(int cnt = 0 ; cnt < nums.length; cnt++) {
if (nums[pre] == 0) {
int tail = pre + 1;
while (tail < nums.length) {
nums[tail-1] = nums[tail];
tail++;
}
pre--;
length--;
}
pre++;
}
while (length < nums.length) {
nums[length] = 0;
length++;
}
}
}
时间复杂度:O(N2),不出意料速度很差
解法二 正经的双指针
i
指针从头到尾遍历,每遇到非零元素,就赋值给j
指针所在位置。
因为j
指针只记录非零元素,所以j
指针一定比i
指针慢。不会有错误覆盖的情况。
class Solution {
public void moveZeroes(int[] nums) {
int j = 0;
for(int i = 0; i < nums.length; i++) {
if (nums[i] != 0) {
nums[j++] = nums[i];
}
}
while (j < nums.length) {
nums[j++] = 0;
}
}
}
时间复杂度:O(N)
小结
双指针篇开始
问题在于没有意识到y指针实际上就是保存的非负元素,不需要每一次遇到0都将后面的元素前移。