目录
1、题目
我们通过阅读题干,可以得到的信息有:我们现在处理的是一个数组,需要剔除数组中值为val的元素(0个或多个),必须进行的是原地修改,不能额外创建新数组。返回的值是修剪过的数组新长度
2、思路
首先我们应该明确一个思路,在无法创建新数组的情况下,我们应当将符合val值的数组元素覆盖或者放到数组最后。最基础的思路应当是暴力循环(使用两层for循环),第一次遍历用来覆盖等于val值的元素,第二次遍历用来更新数组的长度。但是这样做出来的解法,时间复杂度已经大到O(n^2),我们有没有更好的办法,可以降低时间复杂度呢?这样我们就需要考虑到在一层循环内,即完成覆盖又完成遍历,所以我们应该考虑到快慢指针。
该题使用快慢(fast - slow)指针的思想是,用fast指针和slow指针同时遍历数组,fast指针先动,判断fast指针指向的值是否等于val。如果不相等,那么将fast指针指向的值赋给slow指针,然后将slow指针前移。如果相等,则fast指针不进行赋值操作,fast指针继续遍历,slow指针原地不动,等待下一次fast->val = val的情况,用来向前覆盖。在fast指针遍历完数组之后,slow指针之前的元素,一定可以保证不包括与val相等的元素,所以我们直接返回slow的值,就是数组的新长度了。
3、实现
int slow = 0;
int fast = 0;
创建快慢指针,初始位置都为数组首元素的位置。
while(numsSize--)
{
if(nums[fast] != val)
{
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return slow;
使用while(numsSize--)来数组遍历,如果fast指针指向元素,不等于val,则把fast值传给slow,fast和slow同时向后移动。如果fast指针元素等于val,则fast指针自己后移,slow指针保持原地不动,等待下一次判断,用来覆盖前方的val元素。遍历数组完成后,返回slow值,这个时候slow就意味着修剪过后的数组新长度。
4、结果与总结
leetcode通过。
此题主要考察的是我们对于双指针的一个进阶用法——快慢指针,通过两个指针性质不同的特点,在一次遍历中完成两个任务——1、遍历数组,筛选符合条件的元素。2、更新数组长度并返回。快慢指针可以有效地提高循环效率,使得单一循环可以具有更多功能。并且可以有效的降低时间复杂度,从暴力双循环的O(n^2)降低到O(n),是一种很优秀的算法思想。
-1、完整代码
int removeElement(int* nums, int numsSize, int val)
{
int slow = 0;
int fast = 0;
while(numsSize--)
{
if(nums[fast] != val)
{
nums[slow] = nums[fast];
slow++;
}
fast++;
}
return slow;
}