283. 移动零(C++)
题目
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
- 必须在原数组上操作,不能拷贝额外的数组。
- 尽量减少操作次数。
题解与分析
反向遍历—对0元素冒泡
我们需要对数组进行遍历,遭遇到的0元素全部移动到数组的末尾,考虑到正序冒泡的话,遍历的同时,for循环的边界由于容器尾部堆积的0元素,将导致循环边界不断动态的变化,因此我们考虑反向进行遍历,代码如下:
class Solution {
public:
void zeroToEnd(vector<int>& nums, int move,int size) {
for (int i = move; i < size-1; i++) {
int tmp = nums[i+1];
nums[i+1] = nums[i];
nums[i] = tmp;
}
}
void moveZeroes(vector<int>& nums) {
int size = nums.size();
for (int i=size-1; i >= 0; i--) {
if (nums[i] == 0) {
zeroToEnd(nums, i, size);
}
}
}
};
本质是两个for循环的嵌套,时间复杂度为O(n^2)。
正向遍历—交换非0元素
除了遍历数组的for循环的下标i
之外,我们再定义一个下标j
指向容器头部,每当发现非0元素就进行填充并j
向前移位:
-
当
i==j
时,遍历到当前位置不存在非0元素 -
当
j<i
时,遍历到当前位置前已经存在非0元素一旦出现非0元素,
i
和j
俩下标永远不会相等。
0元素会以跟非0元素交换的方式,逐位向尾部移动。代码如下:
class Solution {
public:
void moveZeroes(vector<int>& nums) {
int size = nums.size();
//用于指代当前非0元素的位置
int j = 0;
for (int i = 0; i < size; ++i) {
if (nums[i] != 0) {
//当前非0元素位置随着遍历进行更新非0元素
nums[j] = nums[i];
//当下标不对等,说明有填充0的空位
if (i != j) {
//把0与当前下标的元素进行调换
nums[i] = 0;
}
//如果目前没有非0元素,则目前为止的顺序不需要进行调动
//正常移动下标即可
j++;
}
}
}
};