原题链接:移除元素
对于初学者看不懂的可以看视频讲解,强推Leetcode 27 移除元素 【快慢指针】
个人觉得B站视频的解法更直观理解,虽然本质上都一样。
解题思路
- 用两个指针,快指针和慢指针。快指针用来快速扫描数组元素判断数组元素是否等于val,慢指针用来计数,即最终返回的数组的长度。
- 关键思想就是当快指针不等于val的时候,就把快指针的值赋值给慢指针的值,快慢指针同时往前移,此时相当于慢指针是计数有多少个有效值,先赋值一个,再往前移一个,顺序千万不能乱,先赋值再移动!
- 当快指针遇到连续相等的val时,则快指针继续往下移动,慢指针原地不动,慢指针不动就是快指针没遇到新的元素,直到快指针遇到新的元素才执行赋值操作,否则慢指针不动也不赋值,只有快指针自己往前移。
- 为什么最后直接返回慢指针的数组下标就是此时新的数组元素个数呢?答案在于每次的赋值操作后,快慢指针的值都++,也就是慢指针指到了新数组的下一位,比如新数组有5个元素,最后一个下标为4,而慢指针指到下一位,即下标为5,此时刚好为数组元素个数。
完整代码
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int fast =0,slow = 0; //刚开始两个指针都指向数组第一个元素,下标为0
while(fast < nums.size()){
if(nums[fast] != val){ //判断操作都是由快指针完成
nums[slow] = nums[fast]; //快指针赋值给慢指针
fast++; //赋值操作后,快慢指针同时+1,记得先赋值再+1!!!
slow++;
}else{
fast++; //此时相当于快指针遇到了连续相同的val,此时单纯的快指针+1,慢指针不动
}
}
return slow; //快指针执行完毕越界,此时直接返回慢指针下标即等于数组元素个数
}
};
个人觉得上面的好理解点。
还有卡神的更简洁的,如下
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
if (val != nums[fastIndex]) {
nums[slowIndex++] = nums[fastIndex]; //slowIndex++ 写在里面总感觉怪怪的
}
}
return slowIndex;
}
};
或者
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
if (val != nums[fastIndex]) {
nums[slowIndex] = nums[fastIndex];
slowIndex++; //这下舒坦了,这也是关键
}
}
return slowIndex;
}
};