题目:
Follow up for "Remove Duplicates":
What if duplicates are allowed at most twice?
For example,
Given sorted array nums = [1,1,1,2,2,3]
,
Your function should return length = 5
, with the first five elements of nums being 1
, 1
, 2
, 2
and 3
. It doesn't matter what you leave beyond the new length.
实际上是去重题目的延展,只是去重结果可以允许两个重复。也是来源于
Remove duplicates from sorted array 的思路,设置一个守卫index在上一个元素第一个位置,设置一个计数器,来记住游标i在守卫后面走了count步,若count<2,则说明没有重复,则守卫右移一位,若count>2,则有重复,则守卫右移两位,然后将当前i位置的值覆盖到守卫后面的位置。代码如下:
int removeDuplicateMostTwice2(vector<int>& arr)
{
if (arr.size() <= 2) return arr.size();//不管怎么样,必须先判断数组个数是否小于等于2,如果只有2个 或者 1个 或者没有元素,直接就不用去重操作了
int index = 0, count = 1;
for (int i = 1; i < arr.size(); i++)
{
if (arr[i] != arr[index])
{
arr[++index] = arr[i];//遇到下一个不等于守卫元素的游标位置元素将其复制给守卫元素下一个位置
count = 1;//此时守卫元素计数重新开始
}
else
{
if (count++ > 1) continue;//若守卫元素的数量>1,则游标直接后移一位。
arr[++index] = arr[i];//若守卫元素数量<=1,则将当前游标位置元素赋值给守卫元素下一个(实际上就包含了守卫元素重复?或者不重复的情况)
}
}
return index + 1;//由于从0开始计数,则去重数组的长度为末尾位置+1
}
还有一种更为简洁的方法,直接让当前位置与前前一个位置的元素相比,如果相等,则说明前面的相等的元素数量已经大于2了,因此当前i游标后移,直到遇到一个与守卫index前一个位置元素不等的元素为下一个非重复元素。代码如下:
int removeDuplicateMostTwice1(vector<int>& arr)
{
if (arr.size()<=2) return arr.size();
int index = 1;//守卫从第二个元素开始,或者从第一个元素开始也行,只是写法不一样了
for (int i = 2;i<arr.size();i++)//注意游标要从起始位置的第三个元素算起,因为前面两个,不管是否重复都满足“最多重复2个”的要求
{
if (arr[index - 1] != arr[i])//如果当前游标位置元素等于守卫元素的前一个,说明重复元素已经等于2,接下来重复的元素要被覆盖,直接越过
arr[++index] = arr[i];
}
return index + 1;
}