「这是我参与2022首次更文挑战的第12天,活动详情查看:2022首次更文挑战」
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums =[0,1,0,3,12]
输出:[1,3,12,0,0]
示例 2:
输入: nums =[0]
输出:[0]
双指针
使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。
右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。
注意到以下性质:
- 左指针左边均为非零数;
- 右指针左边直到左指针处均为零。
因此每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变。
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function (nums) {
let fast = 0,
slow = 0;
while (fast < nums.length) {
if (nums[fast] != 0) {
[nums[fast], nums[slow]] = [nums[slow], nums[fast]];
slow++;
}
fast++;
}
return nums;
};
复杂度分析
- 时间复杂度:,其中 为序列长度。每个位置至多被遍历两次。
- 空间复杂度:。只需要常数的空间存放若干变量。
JS特性
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
nums.sort((a,b) => b? 0: -1)
};
一次遍历
这里参考了快速排序的思想,快速排序首先要确定一个待分割的元素做中间点x,然后把所有小于等于x的元素放到x的左边,大于x的元素放到其右边。
这里我们可以用0当做这个中间点,把不等于0(注意题目没说不能有负数)的放到中间点的左边,等于0的放到其右边。
这的中间点就是0本身,所以实现起来比快速排序简单很多,我们使用两个指针i和j,只要nums[i]!=0,我们就交换nums[i]和nums[j]
请对照动态图来理解:
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function (nums) {
if (nums == null) {
return;
}
let j = 0;
for (let i = 0; i < nums.length; i++) {
//当前元素!=0,就把其交换到左边,等于0的交换到右边
if (nums[i] != 0) {
let tmp = nums[i];
nums[i] = nums[j];
nums[j++] = tmp;
}
}
};
复杂度分析
- 时间复杂度: O(n)
- 空间复杂度: O(1)