题目:
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
1 <= nums.length <= 3 * 104-104 <= nums[i] <= 104nums已按升序排列
题解:
首先,这是一道数组类的简单算法题。我们明确循环不变式(loop invariant)的概念,即一组在循环体内、每次迭代均保持为真的性质。
先贴代码:(GO语言)
func removeDuplicates(nums []int) int {
n := len(nums)
if n < 3 {
return n
}
slow, fast := 2, 2
for fast < n {
if nums[slow-2] != nums[fast] {
nums[slow] = nums[fast]
slow++
}
fast++
}
return slow
}
我们设置的循环不变式:slow指针之前的数组元素(不包含目前所指元素)最多有两个重复。同时使用快慢指针的方式。
- 初始
slow设为2,即nums[2]之前的元素不重复,由于nums[2]之前最多有两个元素,一定不会出现两个以上的重复,所以slow位置满足不变式要求。 - 接下来的循环中,如果
nums[fast]与nums[slow-2]不相同,则将nums[fast]赋值给nums[slow]后后移slow,结束本次循环。如果nums[fast]与nums[slow-2]相同,则直接结束本次循环。每次循环,slow位置均满足不变式要求。 - 最终
fast指针遍历完数组元素后,结束整个循环,slow位置满足不变式要求。
因此在循环结束后,slow左侧元素最多只有两个重复元素,符合算法要求。
复杂度分析:
- 时间复杂度:
O(n),其中n是数组的长度。我们最多遍历该数组一次。 - 空间复杂度:
O(1),我们只需要常数的空间存储若干变量。