题目描述:
Given an array nums
, write a function to move all 0
's to the end of it while maintaining the relative order of the non-zero elements.
For example, given nums = [0, 1, 0, 3, 12]
, after calling your function, nums
should be [1, 3, 12, 0, 0]
.
Note:
- You must do this in-place without making a copy of the array.
- Minimize the total number of operations.
代码如下:
class Solution {
public:
void moveZeroes(vector<int>& nums) {
vector<int>::iterator it=nums.begin();
for(int i=0;i<nums.size();i++){ //遍历数组一遍
if(*it==0){
it=nums.erase(it); //如果为0,将其删除,此时it指向被删除的0的下一个元素
nums.push_back(0); //向数组的末尾放一个0
}
else{ //不是0,比较下一个数值
it++;
}
}
}
};
提交后,用时22ms,击败了22.22%的C++程序。
LeetCode提供的最佳解法如下:
Approach #3 (Optimal) [Accepted]
The total number of operations of the previous approach is sub-optimal. For example, the array which has all (except last) leading zeroes: [0, 0, 0, ..., 0, 1].How many write operations to the array? For the previous approach, it writes 0's n−1 times, which is not necessary. We could have instead written just once. How? ..... By only fixing the non-0 element,i.e., 1.
The optimal approach is again a subtle extension of above solution. A simple realization is if the current element is non-0, its' correct position can at best be it's current position or a position earlier. If it's the latter one, the current position will be eventually occupied by a non-0 ,or a 0, which lies at a index greater than 'cur' index. We fill the current position by 0 right away,so that unlike the previous solution, we don't need to come back here in next iteration.
In other words, the code will maintain the following invariant:
All elements before the slow pointer (lastNonZeroFoundAt) are non-zeroes.
All elements between the current and slow pointer are zeroes.
Therefore, when we encounter a non-zero element, we need to swap elements pointed by current and slow pointer, then advance both pointers. If it's zero element, we just advance current pointer.
With this invariant in-place, it's easy to see that the algorithm will work.
首先设置一个变量lastNonZeroFoundAt,初值为0,用来记录“最后一个非零数字的下标”,最后是相对来讲的,设置变量cur=0用来遍历数组,cur的值就是当前遍历到的位置。如果nums[cur]为非零元素,则交换nums[lastNonZeroFoundAt]和nums[cur]的值并且lastNonZeroFoundAt++,cur++,如果nums[cur]为零,则只需cur++,写一个数组模拟一下会更容易理解,官方代码如下:
void moveZeroes(vector<int>& nums) {
for (int lastNonZeroFoundAt = 0, cur = 0; cur < nums.size(); cur++) {
if (nums[cur] != 0) {
swap(nums[lastNonZeroFoundAt++], nums[cur]);
}
}
}