Day05已经是三天前的事情了,断更了三天,真的是上班强度太累了,我只要不太累,都要坚持每日一题的去坚持,当然我的JavaScript基础回顾还在继续,其实在断更的这几天里,我在学习过程中做了求闰年,九九乘法表,冒泡排序和选择排序,也算是没有间断算法练习了,不说这么多废话了,上题目:
283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
提示:
1 <= nums.length <= 104-231 <= nums[i] <= 231 - 1
实现:
-
从Day05以后,不再写python了,那也是之前学python的时候写的,也就学了个基础语法,现在还是专注前端吧
-
我最开始想使用filter + concat来实现的,这个确实能实现,但是这两个方法都会生成新的数组,不满足题目要求了,因为题目明确要求:
必须在不复制数组的情况下原地对数组进行操作。/** * @param {number[]} nums * @return {void} Do not return anything, modify nums in-place instead. */ var moveZeroes = function(nums) { nums = nums.filter(i => i !== 0).concat(nums.filter(i => i === 0)) }; -
我想着用分割字符串,就是出现个0,我就删除他,然后再在末尾追加一个,也肯定能实现,于是就有了下面这个方法,但是这个方法相当于做了两次循环,一个是for..0f,一个是indexOf,这样时间复杂度就是O(n^2)
/** * @param {number[]} nums * @return {void} Do not return anything, modify nums in-place instead. */ var moveZeroes = function(nums) { for(i of nums) { if(i === 0) { nums.splice(nums.indexOf(i), 1) nums.push(0) } } }; -
为了降低时间复杂度,我想着观察了一下,好像有以下规律
- 第一个非零元素,我让他去数组的第一个,那也就是说我把nums[0]和这个元素交换位置
- 第二个非零元素,我让他去数组的第二个,那也就是说我把nums[1]和这个元素交换位置
- 第三个......
- 第四个......
- 总结,我弄个下标
index =0,遇到非零元素换一下,然后++,就能实现,这个我查了一下,叫双指针
/** * @param {number[]} nums * @return {void} Do not return anything, modify nums in-place instead. */ var moveZeroes = function(nums) { let index = 0 for(let i = 0; i < nums.length; i++) { if(nums[i] !== 0) { [nums[index], nums[i]] = [nums[i], nums[index]] index++ } } };
进阶: 你能尽量减少完成的操作次数吗?
- 这个是D老师给的滚雪球的方法,有点冒泡的影子(但Deepseek说不是,他说是插入算法的优化),
想知道原理的自己去问Deepseek吧
var moveZeroes = function(nums) {
let snowBallSize = 0;
for (let i = 0; i < nums.length; i++) {
if (nums[i] === 0) {
snowBallSize++; // 遇到零时,"雪球"增大
} else if (snowBallSize > 0) {
// 将当前非零元素与雪球最前面的零交换
nums[i - snowBallSize] = nums[i];
nums[i] = 0;
}
}
};