题目链接:https://leetcode-cn.com/problems/move-zeroes/
参考链接:
https://leetcode-cn.com/problems/move-zeroes/solution/yi-dong-ling-by-leetcode/
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
示例 1:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
- 必须在原数组上操作,不能拷贝额外的数组。
- 尽量减少操作次数。
- 这个题可以拆解成两个步骤:
- 数组前面为数组中的非零元素[按顺序],
- 数组后面全是零
- 所以就涉及到去零和补零的操作,这两个操作的顺序和方法不同就有了多个不同的解法
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
// 双指针去零,慢指针指向存储位置,快指针遍历数组,遇到非零元素就将其放到慢指针的位置。遍历一遍后完成移动。最后通过,jsAPI的`fill`补零
var moveZeroes = function(nums) {
var k = 0;
for(var i = 0; i < nums.length; i++){
if(nums[i] === 0){
continue;
}
nums[k] = nums[i];
k++;
}
nums.fill(0, k, nums.length)
};
// 通过filter找到非零元素(去零),fill构建全部为零的数组(补零),splice和扩展运算符进行数组重组,本质上还是去零和补零
var moveZeroes = function(nums) {
var numsF = nums.filter(v => v !== 0);
nums.splice(0, nums.length, ...numsF, ...Array(numsF.length).fill(0));
};
// 一次遍历,遇到零就通过splice删除(去零),然后在结尾push0(补零)
var moveZeroes = function(nums) {
let n = nums.length;
for(let i=n-1;i>=0;i--){
if(nums[i]===0){
nums.splice(i,1)
nums.push(0)
}
}
};
- 双指针,也是快指针和慢指针交换元素,是思路一的第一种解法的进阶版,思路一只考虑到前N个为非零元素,想着覆盖就好,然后补零。
- 如果扩宽一下思路,什么时候需要交换元素呢,就是前面有元素为0[一个或者多个],当前元素不为0的时候,将当前元素和第一个为0的元素交换。
- 也就是说我们需要一个快指针遍历数组的同时,需要一个慢指针指向第一个为0的,也就是当有元素为0时,慢指针停止移动,快指针继续向前,找到不为0的值,使两者交换,并且向前移动慢指针。
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
let j = 0;
for (let i = 0; i < nums.length; i++) {
if (nums[i] !== 0) {
// 普通交换元素,这里也是可以加一个判断:慢指针是否指向元素为0
[nums[j], nums[i]] = [nums[i], nums[j]];
// 因为只有在慢指针指向元素为0,而快指针指向元素不为0的时候才需要交换,而且交换的元素为0,所以可以进行一下操作
// if (nums[j] === 0) {
// nums[j] = nums[i];
// nums[i] = 0;
// }
j++
}
}
};
- 还是双指针的思路,最开始只想到了覆盖,没有想到可以替换
- 双指针的思路在数组的算法题中经常使用,以后要多考虑一下,而且要思考一下有没有有没有更有解
- 交换元素可以用js的解构