题目描述
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
提示:
1 <= nums.length <= 10^4
-2^31 <= nums[i] <= 2^31 - 1
**进阶:**你能尽量减少完成的操作次数吗?
思路
笔者使用快慢指针法来解决这题。快慢指针并行,当慢指针遇到0时,慢指针停下,让快指针继续向前移动找到第一个非0元素,然后让快慢指针所指元素进行交换。当快指针移动到数组末尾的时候就已经交换完成了。
代码
C++版:
cpp
class Solution {
public:
void moveZeroes(vector<int>& nums) {
// 快慢指针法
int slow=0;
int fast=0;
while(fast<nums.size()){
if(nums[slow]==0){
// 快指针移动到下一个非0元素
while(fast<nums.size()-1 && nums[fast]==0){
fast++;
}
if(fast<=nums.size()-1 && nums[fast]!=0 && slow!=fast){
// 交换慢指针的0与快指针的非0元素
swap(nums[slow],nums[fast]);
}
}
slow++;
fast++;
}
}
};
Python版:
python
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
slow=0
fast=0
while fast<len(nums):
if nums[slow]==0:
while fast<len(nums)-1 and nums[fast]==0:
fast+=1
if fast<=len(nums)-1 and nums[fast]!=0 and slow!=fast:
nums[slow],nums[fast]=nums[fast],nums[slow]
slow+=1
fast+=1
需要注意的地方
1.本题思路也可以这么描述:
左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变。
2.第二种解法:
记元素向左的偏移量为 offset,初始 offset = 0。每次发现元素为 0 时增加偏移量,发现元素非 0 且偏移量非 0 时偏移元素。
cpp
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int offset = 0;
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == 0) {
offset++;
} else if (offset != 0) {
nums[i - offset] = nums[i];
nums[i] = 0;
}
}
}
};
/*
作者:Shawxing精讲算法
链接:https://leetcode.cn/problems/move-zeroes/solutions/2821184/san-chong-jie-fa-duo-yu-yan-you-pei-tu-b-1d3s/
来源:力扣(LeetCode)
*/