Problem: 283. Moving zero
Article Directory
train of thought
First of all, let's talk about the idea of this question
- This question can mainly be classified into the question type of [Array Division/Array Blocking]. We divide all elements in an array into two intervals, with non-zero elements on the left and zero elements on the right
- The first thing we think of to solve this kind of problem is [Double Pointer Algorithm]. Students who have studied C language should be able to know that pointers are more cumbersome and complicated. If you are interested in learning, you can check out my article link
- But here we don't need to use
int*
this kind of pointer, but directly use the array subscript as a pointer
Ok, then let's take a look at what this double pointer is like and how to use it
- The role of the two pointers
- [cur]: scan the array from left to right, traverse the array
- [dest]: the last position of the non-zero element in the processed range
- It can be seen that
cur
we are used to traverse the array, from[cur, n - 1]
is the element that has not been processed; then from[0, cur]
is the element that has been processed, but the requirement of this question is that we have to divide [zero elements] and [non-zero elements], So we can divide the previous interval into[0, dest]
and[dest + 1, cur - 1]
To sum up:
[0, dest] [dest + 1, cur - 1] [cur, n - 1]
[0, dest]
- non-zero elements[dest + 1, cur - 1]
- zero element[cur, n - 1]
- unprocessed elements
Algorithm Diagram Analysis
Next, we will simulate the process of solving the problem by drawing an algorithm diagram
- Let's take the first example given in the title as an example to explain, because we haven't processed any non-zero elements at the beginning, so there is no data for
[0, cur - 1]
this interval, so at the beginning we You can place the [dest] pointer at -1
- Because we need to move the non-zero elements to the front, so if we encounter a 0 element,
cur++
just leave it at this position
- Then when we encounter non-zero elements, we need to exchange them to the front, then our
[0, dest]
interval is used to store non-zero elements. If there is one more element at this time,dest
we need to add 1, which originally points to - 1 this position, then we can use++dest
to complete
- Next, when the data is exchanged, we can compare the above three intervals, and we can find that the leftmost is a non-zero element, the middle is a 0 element, and the right is an element to be processed. Next we encounter 0 elements, so
cur++
cur
After moving back, we encountered a non-zero element again, continue to let itdest
go up and exchange the elements at the two positions
- Now let's look at these three intervals again. The left side is still [non-zero element], the middle is [0 element], and the right side is [pending element]
- Then after encountering a non-zero element, continue to let
++dest
, and then do the exchange
- Finally, let's take a look at the entire range of elements after processing: the non-zero elements are all in the front, while the 0 elements are in the back, and
[cur, n - 1]
this section of the range does not exist, indicating that there are no more elements to be processed
the complexity
Next, let's analyze the space-time complexity of this question.
- time complexity:
The core idea of this algorithm refers to the interval division of [Quick Sort]. Here, in the process of continuously traversing the array, we use the middle 0 as the division, and then the left side is non-zero elements, and the right side is unprocessed elements. In the process of processing, we only traverse the array once, so the complexity is O ( n ) O(n)O ( n )
- Space complexity:
In this question, we did not open up additional space, so the complexity is O ( 1 ) O(1)O(1)
Code
class Solution {
public:
void moveZeroes(vector<int>& nums) {
for(int dest = -1, cur = 0; cur < nums.size(); ++cur)
{
if(nums[cur] != 0)
{
swap(nums[++dest], nums[cur]);
}
}
}
};