【Python刷力扣hot100】283. Move Zeroes
问题
给定一个整数数组 nums,将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
注:必须在原地完成操作,不能创建数组的副本。
例1:
Input: nums = [0,1,0,3,12]
Output: [1,3,12,0,0]
例2:
Input: nums = [0]
Output: [0]
约束:
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
分析
1
可以新建一个数组,把非零元素依次放入其中,之后把剩下的位置都补0即可。但与题意不符。
2
我们可以从前往后遍历数组,碰到0就把0后移动,若有连续的0,就把这些0都往后移。这个思路的代码略麻烦。
也可以从后往前遍历,每次碰到一个0,就先标记这个0的位置,之后把这个0移到末尾,然后回到刚才的位置继续往前遍历
还可以从前往后遍历,把非零数字左移,用一个指针cur
记录序列的最后一个元素,之后把每个遇到的非零数字都移动到最后一个位置,之后cur
自增1。最后再从cur
开始把后面的元素都变为0即可。
解1:
采用刚才思考得到的思路:从后往前遍历,每次碰到一个0,就先标记这个0的位置,之后把这个0移到末尾,然后回到刚才的位置继续往前遍历
class Solution:def moveZeroes(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""for i in range(len(nums)-1,-1,-1):if nums[i]==0:current_i=iwhile current_i!=len(nums)-1:# 不断交换,把0移动到最后t=nums[current_i]nums[current_i]=nums[current_i+1]nums[current_i+1]=tcurrent_i+=1return
这个思路能过,但是时间消耗比较大
解2:双指针
相当于对上面从前往后遍历的思路进行了改进。
我们可以使用两个指针,左指针l
指向已经处理好的序列的尾部,右指针r
指向未处理好序列的头部。l和r都初始化为0。
之后不断将右指针r
右移,当r
指向非零数时,就将l
和r
指向的数字交换,之后令l
自增1,过程中:
l
左边均为非零数;r
左边直到l
处均为零
相当于把数组分成了2类,0和非0,r
负责按顺序找非0数,l
负责按顺序存储知道的非0数
这个思路与快速排序(Quick Sort)中的分区(partition)过程相似
时间复杂度O(n)O(n)O(n):相当于遍历了一次数组
空间复杂度O(1)O(1)O(1):使用的空间大小是固定的
class Solution:def moveZeroes(self, nums: List[int]) -> None:"""Do not return anything, modify nums in-place instead."""n=len(nums)l=r=0while r<n:if nums[r]!=0:# 交换nums[l]和nums[r]t=nums[l]nums[l]=nums[r]nums[r]=tl+=1r+=1return
参考
https://leetcode.cn/problems/move-zeroes