题目:
给定一个数组 nums
,编写一个函数将所有 0
移动到数组的末尾,同时保持非零元素的相对顺序。
请注意 ,必须在不复制数组的情况下原地对数组进行操作。
1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
题解:
首先,这是一道数组类的简单算法题。我们明确循环不变式(loop invariant)的概念,即一组在循环体内、每次迭代均保持为真的性质。
先贴代码:(GO语言)
func moveZeroes(nums []int) {
left, right, n := 0, 0, len(nums)
for right < n {
if nums[right] != 0 {
nums[left], nums[right] = nums[right], nums[left]
left++
}
right++
}
}
我们设置的循环不变式:left
指针之前的数组元素(不包含目前所指元素)不为0
。
- 初始
left
设为0
,即nums[0]
之前的元素不为0
,由于nums[0]
之前没有元素,left
位置满足不变式要求。 - 接下来的循环中,如果
nums[right]
不为0
,则与nums[left]
进行交换后后移left
,结束本次循环。如果nums[right]
为0
,则直接结束本次循环。每次循环,left
位置均满足不变式要求。 - 最终
right
指针遍历完数组元素后,结束整个循环,left
位置满足不变式要求。
因此在循环结束后,left
左侧元素均为非0
元素,且由于right
按数组顺序遍历,非0
元素保持原数组的有序性,符合算法要求。
更容易理解的是,循环中也可不使用交换,而是如果nums[right]
不为0
,直接赋值给nums[left]
,right
的循环结束后,多写一个循环,将left
及left
之后的数组元素置零。
复杂度分析:
- 时间复杂度:
O(n)
,其中n
为序列长度。每个位置至多被遍历两次。 - 空间复杂度:
O(1)
。只需要常数的空间存放若干变量。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。