「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」
题目
283. 移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
示例 1:
输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]
示例 2:
输入: nums = [0]
输出: [0]
解法一
思路:
原地排序,但是会改变元素的相对顺序,虽然过不了,但是也是一个思路,还是写一下。
定义一个右指针lr,遍历数组,如果遇到0则与右指针所对应的元素交换位置,lr--。
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
let len = nums.length;
let lr = len - 1;
for(let i=0;i<len;i++){
if(i <lr){
if(nums[i] == 0){
[nums[i],nums[lr]] = [nums[lr],nums[i]];
lr--;
}
}
}
return nums;
};
解法二
思路:
这个方法我也不知道该叫什么,脑海里有这个思路就写出来了。
步骤如下
- 定义一个计数器count,记录从遇到第一个0开始,0的个数,当遇到非0元素时,计数器置为0。
- 从左往右遍历数组,遇到0则将count++,并将当前项与之后的第count项交换位置,并且i--,因为我们要看一下交换过来的元素是不是0。
- 如果是第一次遇到0,那么第count项就是下一项。
- 假想,如果连续两个都是0,那么遇到第一个0后,交换过来的还是0,我们的就又count++了,count就是2了,那么就将当前项与之后的第2项交换位置
- 遇到非0元素,则将count重置为0。
这个思路就有点像踢皮球,遇到0就往后踢。连续遇到0就把0题远一点。
这个解法只是我个人的一个想法,大家不必深究,哈哈。
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
let len = nums.length;
let count = 0;
for(let i=0;i<len;i++){
if(nums[i] == 0 && (i+count)<len-1){
count++;
[nums[i],nums[i+count]] = [nums[i+count],nums[i]];
i--;
}else{
count = 0;
}
}
return nums;
};
解法三
思路:
双指针解法。
- 定义一个pl用户记录包含非0元素的区间的右边界,即 [0,pl]内的元素都是非0,开始pl=-1;
- 遍历数组,当遇到0则不管;遇到非0,则将pl++,即给包含非0的区间扩容。然后将当前非0元素与pl对应的元素交换位置。
- 由于我们的下标i一定是在pl的前面的,多以i和pl交换,换过来的一定是0,所以直接继续遍历即可。
/**
* @param {number[]} nums
* @return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
let pl = -1;
let len = nums.length;
for(let i=0;i<len;i++){
if(nums[i] !=0){
pl++;
[nums[i],nums[pl]] = [nums[pl],nums[i]]
}
}
return nums;
};
复杂度分析
时间复杂度:O(n),n为数组元素的个数。
空间复杂度::O(1),不用额外使用空间存储元素。