这道题要求我们原地删除重复出现的元素,使得每个元素最多出现两次,并返回删除后数组的新长度。同时,题目要求使用 O(1) 的额外空间来实现。
一、双指针解法
思路:
由于数组是有序的,我们可以使用双指针法来解决这个问题。我们可以定义两个指针 slow
和 fast
分别指向处理后的数组的末尾和当前处理的位置。
- 从第三个元素开始,我们比较当前元素与慢指针向前两步的元素是否相同。
- 如果相同,则说明当前元素出现次数已经超过两次,直接跳过;
- 如果不同,则将当前元素复制到慢指针位置,并移动慢指针。
算法实现:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int len = nums.size();
int slow = 2; // 慢指针,初始位置为2
int fast = 2; // 快指针,初始位置为2
while (fast < len) {
if (nums[slow - 2] == nums[fast]) {
fast++; // 当前元素出现次数已经超过两次,快指针继续向前移动
} else {
nums[slow] = nums[fast]; // 复制当前元素到慢指针位置
slow++; // 慢指针向前移动
fast++; // 快指针向前移动
}
}
return slow; // 返回处理后数组的新长度
}
};
二、测试数据 [0,0,1,1,1,1,2,3,3] 的处理过程:
初始时,数组为 [0,0,1,1,1,1,2,3,3]
。
- 初始时,慢指针和快指针均指向索引位置2,对应元素为1。
- 比较当前元素1和慢指针向前两步的元素0是否相同,不同,因此将1复制到慢指针位置,即
nums[2] = 1
,慢指针和快指针都向前移动一步。 - 比较当前元素1和慢指针向前两步的元素0是否相同,相同,因此跳过当前元素1,快指针向前移动一步。
- 比较当前元素1和慢指针向前两步的元素1是否相同,不同,因此将1复制到慢指针位置,即
nums[3] = 1
,慢指针和快指针都向前移动一步。 - 比较当前元素1和慢指针向前两步的元素0是否相同,相同,因此跳过当前元素1,快指针向前移动一步。
- 比较当前元素1和慢指针向前两步的元素1是否相同,不同,因此将1复制到慢指针位置,即
nums[4] = 1
,慢指针和快指针都向前移动一步。 - 比较当前元素1和慢指针向前两步的元素1是否相同,相同,因此跳过当前元素1,快指针向前移动一步。
- 比较当前元素2和慢指针向前两步的元素1是否相同,不同,因此将2复制到慢指针位置,即
nums[5] = 2
,慢指针和快指针都向前移动一步。 - 比较当前元素3和慢指针向前两步的元素1是否相同,不同,因此将3复制到慢指针位置,即
nums[6] = 3
,慢指针和快指针都向前移动一步。 - 比较当前元素3和慢指针向前两步的元素2是否相同,不同,因此将3复制到慢指针位置,即
nums[7] = 3
,慢指针和快指针都向前移动一步。
处理完成后,数组变为 [0,0,1,1,2,3,3]
,返回慢指针位置7,表示处理后数组的新长度为7。
结语
通过上述双指针的方法,我们可以在 O(n) 的时间复杂度内解决这个问题,同时不使用额外的空间,满足了题目的要求。