27. 移除元素
双指针法(前后指针)
vector容器是顺序存储,所以不能单独删除数组中某个元素,只能覆盖!
因为要求“原地”删除,所以想要用“双指针法”
自己的双指针思路是:
-
定义两个指针,分别指向数组的头尾
-
first负责定位到val的位置,last负责定位到非val的位置,然后把非val和val交换,最终使所有val都聚在数组后面,再调用erase删除所有val
-
两个指针指向的情况如下
*first *last operation =val =val last– =val !=val first++,last– !=val !=val first++ !=val =val first++,last–
过程中忽略了以下几个细节
-
数组为空的情况!
-
数组长度为1时可以直接返回结果,会更快
-
数组长度为2时也有四种情况,直接判断,返回结果,会更快
AC代码
//时间复杂度:O(N)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
if(nums.size()==0)
return 0;
if(nums.size()==1)
return nums[0]==val?0:1;
if(nums.size()==2)
{
if(nums[0]==val&&nums[1]==val)
return 0;
if(nums[0]==val)
{nums[0]=nums[1];return 1;}
if(nums[1]==val)
return 1;
return 2;
}
vector<int>::iterator first=nums.begin();
vector<int>::iterator last=nums.end();
last--;
while(first<last)
{
if(*first==val&&*last!=val)
{
int temp=*first;
*first=*last;
*last=temp;
first++;last--;
}
else if(*first!=val&&*last==val)
first++,last--;
else if(*first==val&&*last==val)
last--;
else
first++;
}
if(*first==val)
nums.erase(first,nums.end());
else
nums.erase(++first,nums.end());
return nums.size();
}
};
看到官方题解,才知道自己的思路是对的,但是写的太复杂了!
优化代码:
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int left=0,right=nums.size();
while(left<right)
{
if(nums[left]==val)
nums[left]=nums[right-1],right--;
else
left++;
}
return left;
};
双指针法(快慢指针)
看到网上的题解,用的是“快慢指针法”
思路
- 定义快慢指针
- slow指向要被覆盖的位置,fast指向下一个位置
- 如果slow指向的元素值是val,则fast右移一个位置,并用其元素值覆盖slow
- 如果slow指向的元素值不是val,则slow,fast都右移
//时间复杂度:O(N)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int len = nums.size();
int slow= 0;
for (int fast = 0; fast< n; fast++) {
if(nums[slow]!=val)
nums[slow++]=nums[fast];
}
return left;
}
};
因为题目说元素顺序可以改变,所以,可以考虑先对数组排序,再用slow定位到第一个val,fast定位到最后一个val的下一个位置,然后把后面的元素覆盖掉所有Val
具体代码。。以后再写吧