做这道题的时候已经忘了它的姊妹篇Remove Duplicates from Sorted Array 这题是怎么做的了,后来查了以前的代码(还是用java写的不过现在用C++写了),嗯,已经忘记为啥那样写的了。。。那就索性重新开始!
此题说在一个有序数组中可以存在至多两个重复的数字,三个以上就需要将多余的数字剔除。我的想法是利用C++ STL中的erase()方法将多余的剔除。
大体的思路如下:
定义两个标识变量s和e,分别代表一段重复数字序列的起始位置和结束位置;
在一个for循环中 依次判断当前数字与它相邻的数字是否不相等或者当前数字是数组的最后一个,这个判断条件代表一段重复数字序列的结束(不论该数字的重复次数是否大于等于3,即需要剔除多余的数字),接下来是判断这段重复数字序列的重复次数是否大于等于3(利用s和e之差判断)
a.如果s和e的差小于等于1说明重复次数在2以内不需要剔除多余的,更新s和e值;
b.如果s和e的差大于等于2说明需要剔除多余的数字,利用C++ STL中的erase()方法,同样更新s和e的值;
具体代码如下:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int s=0,e=0,del_count=0,len=nums.size();
if(len<=1)
return len;
for(int i=0;i<nums.size();){
if(i==nums.size()-1||(nums[i]!=nums[i+1]&&i+1<nums.size())){
e=i;
if(e-s<=1){
e=0;
s=i+1;
i++;
}
else{
vector<int>::iterator ite;
//移除多余的数字
int cur=nums[i];
for(ite=nums.begin()+s+2;ite!=nums.end();){
if(*ite==cur){
ite=nums.erase(ite);
del_count++;
}
else
break;
}
s=i+1-del_count;
i=s;
}
}
else{
i++;
}
}
return nums.size();
}
};
AC后,又学习了其他人的做法,发现自己的想法并不是那么好,所以进行改进。
大体思想如下:
定义了一个标志变量k,用于记录“剔除”多余数字后的符合题目要求的数字在数组中的位置;
同样是在for循环中依次判当前数字与array[k-2]是否相等,如果相等则不做任何处理即不更新array[k]处的数字;如果不相等则更新array[k]处的数字为当前数字,k++;
具体代码如下:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int k=0;
for(int i=0;i<nums.size();i++){
if(i==0||i==1){
nums[k++]=nums[i];
}
else{
if(nums[i]==nums[k-2]){
}else{
nums[k++]=nums[i];
}
}
}
return k;
}
};
改进后的思想感觉比我自己的第一种思想“聪明”一些,说明自己还要多多向前辈们学习,并且感觉自己再解题技巧上有所欠缺,对于“双指针”这一类的题好像归纳总结的不多,朋友向我推荐了编程之美这本书,准备去读读。
做完了这个题,就顺便复习了一下Remove Duplicates from Sorted Array 这道题,这两道题的解题思想算是“师出同门”吧,这里就不再详述了。
具体代码如下:
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
if(nums.size()<=1)
return nums.size();
int k=0;
for(int i=1;i<nums.size();i++){
if(nums[i]!=nums[k]){
nums[++k]=nums[i];
}
}
return k+1;
}
};
补充:
其实,根据第一种想法在编码的过程中,一开始想用那个泛型算法remove,但是总有一个bug使结果出错我就放弃使用remove改用C++ STL erase,AC后又回过头来仔细研读了remove的一些例子、reference及源码,才彻底搞懂了这个方法。。。
既然remove和erase都是删除,下面来总结下两者的用法~
一、remove其实是将不应该被删掉的元素赋值到应该被删除的元素的位置上,这算是另一种形式上的删除吧。
这里贴出remove方法的源码:来自于http://www.cplusplus.com/reference/algorithm/remove/
<pre><code><var>template</var> <<var>class</var> ForwardIterator, <var>class</var> T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, <var>const</var> T& val)
{
ForwardIterator result = first;
<var>while</var> (first!=last) {
<var>if</var> (!(*first == val)) {
*result = *first;
++result;
}
++first;
}
<var>return</var> result;
}</code>
分析下源码发现,这种思想与Remove Duplicates from Sorted Array系列的两道题的解法有异曲同工之妙。同样是两个位置指针(变量)进行比较和替换,换句话说leetcode上的这两道题更像是对remove源码的一种灵活应用~
二、erase就是真正意义上的删除了,因为容器或者数组的大小会减小;而remove就不会使容器或者数组的大小减小,因为它并不是真正意义上的删除。
通常会将remove和erase这两种方法一起使用,
eg.nums.erase(remove(nums.begin(),nums.end(),val),nums.end());
nums是容器或者数组,remove方法返回的是“删除”某些元素后新的元素范围的下一个位置处的iterator,从这个iterator位置处开始到nums.end() 就是erase方法要删除的元素范围了,val是要删除的元素。