前言
昨天第一天时间太赶,没来得及把剩下的一题看了,今天补回来。
移除元素
(用时1小时)
这道题的解法有两种,一种是暴力破解,一种是快慢指针法。
注意题目要求空间复杂度是O(1),这表明需要在同一个数组中进行处理。
暴力破解
暴力破解很简单,两层嵌套循环。
-
外层循环用于遍历整个数组,如果找到需要移除的元素,则开启内层循环。
-
内存循环用来将该需移除元素后面的所有元素向前挪一位(题目要求元素原顺序不可变)。这样的时间复杂度大概是O(n^2)
注意重点
暴力破解时,有个地方要注意:所有元素移完位置后,外层循环的循环遍历(一般是那个i),要 i-- 。
-
i--主要是因为,我们原本在这个第i位上发现他是要移除的,才将后面所有的元素前移一位。
-
移完后第i位已经不是原来的那个元素了,此时需要再判断移动后的第i位是不是恰好也是要移除的元素
-
即可能会有连续几个元素都是要移除的
快慢指针法
快慢指针需要小绕一下。
-
快指针是对整个数组进行探索遍历,慢指针是对新的数组进行赋值遍历
-
如果反应不过来,可以先把慢指针当成一个新的空的数组的指针。快指针对旧的数组进行遍历:
1.如果不是需要移除的元素,则利用慢指针加入新数组的空位中,慢指针向后移一位。快指针后移一位。
2.如果是需要移除的元素,新数组和慢指针不做处理。快指针后移一位。
-
两个数组的想好了后,一个数组就简单了。只是将两个指针放到了同一个数组上进行处理。慢指针一定会等于或慢于快指针,因此不会出现问题。
注意重点
快慢指针法在写的时候,重点要考虑以下几点:(
-
arr[fastIndex] != val时,要做什么?
-
arr[fastIndex] = val时,要做什么?
-
return slowIndex? 还是slowIndex+1? 还是slowIndex-1?
以下是个人的一些想法:
-
nums[fastIndex] != val时,要做什么?
不等于时,表示该值不用被跳过,slowIndex要让其放入新数组。更新slowIndex,fastIndex继续探索既可。
-
nums[fastIndex] = val时,要做什么?
等于时,表示该值要被跳过,slowIndex不能放入新数组。让fastIndex继续向前探索即可。
-
return什么?
slowIndex始终是等待赋值的下一位,因此只用return slowIndex即可。
代码实现
暴力破解
/// <summary>
/// 暴力破解法
/// </summary>
/// <param name="nums"></param>
/// <param name="val"></param>
/// <returns></returns>
public int RemoveElementFun2(int[] nums, int val)
{
int cnt = 0;
for (int i = 0; i < nums.Length - cnt; i++)
{
if (nums[i] == val)
{
for (int j = i + 1; j < nums.Length - cnt; j++)
{
nums[j - 1] = nums[j];
}
cnt++;
i--;
}
}
return nums.Length - cnt;
}
双指针法
/// <summary>
/// 快慢指针方法
/// </summary>
/// <param name="nums"></param>
/// <param name="val"></param>
/// <returns></returns>
public int RemoveElementFun(int[] nums, int val)
{
int fastIndex, slowIndex;
fastIndex = slowIndex = 0;
while (fastIndex < nums.Length)
{
if (nums[fastIndex] != val)
{
nums[slowIndex] = nums[fastIndex];
fastIndex++;
slowIndex++;
}
else
{
fastIndex++;
}
}
return slowIndex;
}