[路飞]_leetcode刷题_283. 移动零

131 阅读3分钟

「这是我参与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;
};

解法二

思路:

这个方法我也不知道该叫什么,脑海里有这个思路就写出来了。

步骤如下

  1. 定义一个计数器count,记录从遇到第一个0开始,0的个数,当遇到非0元素时,计数器置为0。
  2. 从左往右遍历数组,遇到0则将count++,并将当前项与之后的第count项交换位置,并且i--,因为我们要看一下交换过来的元素是不是0。
    • 如果是第一次遇到0,那么第count项就是下一项。
    • 假想,如果连续两个都是0,那么遇到第一个0后,交换过来的还是0,我们的就又count++了,count就是2了,那么就将当前项与之后的第2项交换位置
  3. 遇到非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;
};

解法三

思路:

双指针解法。

  1. 定义一个pl用户记录包含非0元素的区间的右边界,即 [0,pl]内的元素都是非0,开始pl=-1;
  2. 遍历数组,当遇到0则不管;遇到非0,则将pl++,即给包含非0的区间扩容。然后将当前非0元素与pl对应的元素交换位置。
  3. 由于我们的下标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),不用额外使用空间存储元素。