此专栏所有文章仅用于自我学习记录。
题目:
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/move-zeroes
解答:
先是很自然的一个解答。照常理思维,先去把前面非0的部分排序排好,顺便统计0的个数,用到i和j两个变量。第二步,再末尾重写对应个数的0.
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
i = j = 0
n = len(nums)
while j<n:
if nums[j]==0:
i +=1
j +=1
else:
nums[j-i] = nums[j]
j+=1
while i>0:
nums[n-i] = 0
i -=1
接着试着优化,想把这两个一步做,但是不行,下面是错误示范:
错误示范,搬运和重写不能同时进行,末尾的非0数会丢失掉
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
"""
Do not return anything, modify nums in-place instead.
"""
i = j = 0
n = len(nums)
while j<n-i:
if nums[j]==0:
i +=1
nums[n-i] = 0
else:
nums[j-i] = nums[j]
j+=1
最后是官方的比较巧妙的解答,一次循环完成。
同时swap,或者python里面的交换,速度还是很快的,对于性能提升有帮助,相比于分两次写操作,优先考虑交换。
整体上是双指针的思想,以及顺序处理的思想。构造快慢两个指针,快指针表示处理完成的末端;慢指针表示非0的末端,然后遇到新的数,通过交换到合适的位置,来迭代完成处理。
注意,因为这里后一个序列全部都是0,可以这么做。如果前面是正数序列,后面不是0序列是非负数序列,那么最后你会发现由于交换次数不一定和非负数序列个数相同,那么最后非负数序列的顺序会变掉的,因此这样的方法可以保存前面一个序列的顺序,但是保存不了后面一个序列的顺序。算是局限性吧。代码在下面:
class Solution:
def moveZeroes(self, nums: List[int]) -> None:
n = len(nums)
left = right = 0
while right < n:
if nums[right] != 0:
nums[left], nums[right] = nums[right], nums[left]
left += 1
right += 1
# 作者:LeetCode-Solution
# 链接:https://leetcode-cn.com/problems/move-zeroes/solution/yi-dong-ling-by-leetcode-#solution/
# 来源:力扣(LeetCode)
官方给的解析:
方法一:双指针
思路及解法
使用双指针,左指针指向当前已经处理好的序列的尾部,右指针指向待处理序列的头部。
右指针不断向右移动,每次右指针指向非零数,则将左右指针对应的数交换,同时左指针右移。
注意到以下性质:
左指针左边均为非零数;
右指针左边直到左指针处均为零。
因此每次交换,都是将左指针的零与右指针的非零数交换,且非零数的相对顺序并未改变
作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/move-zeroes/solution/yi-dong-ling-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。