题目
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成
解法1:双指针法
该题和leetcode第26题类似,不过本题的差异是每个重复最多出现两次。那么应该通过一个变量来记录重复的次数,如果超过2两次才能删除掉后面重复的元素。
代码如下:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if (nums.empty()) {
return 0;
}
int left = 0;
int right = 1;
int count = 0;
while (right < nums.size()) {
// 如果前后值一致,需要移动右指针,并且增加相等次数计数
if (nums[left] == nums[right]) {
++right;
++count;
// 重复一次表示已经有两个数了,如果重复次数超过1次则表示至少有3个相同的数
if (count <= 1) {
++left;
// 若left指针向右移动,需要将值更新成与left指针移动前的值
nums[left] = nums[left - 1];
}
continue;
}
count = 0; // 当值不相等后,需要重置相等次数
++left;
if (left != right) {
nums[left] = nums[right];
}
++right;
}
return left + 1;
}
};
时间复杂度为O(n)
,空间复杂度为O(1)
,执行结果如下:
解法2
解法1是每个元素最多出现两次,那么可以将这个问题进行泛化,每个元素最多可以保留N次。由于最多保留N个重复元素,那么如果数组小于N,可无脑保留,否则看当前的值与当前位置的前N个值比较,如果不等则可以保留,否则不能保留。
代码如下:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
return removeDuplicates(nums, 2);
}
private:
int removeDuplicates(vector<int>& nums, int n)
{
int len = 0;
for (int i = 0; i < nums.size(); ++i) {
if ((i < n) || (nums[i] != nums[len - n])) {
if (len != i) {
nums[len] = nums[i];
}
++len;
}
}
return len;
}
时间复杂度为O(n)
,空间复杂度为O(1)
,执行结果如下: