题目描述

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。

假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:

  • 更改 nums 数组,使 nums 的前 k 个元素包含不等于 val 的元素。nums 的其余元素和 nums 的大小并不重要。
  • 返回 k

示例 1:

plaintext
1
2
3
4
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,_,_]
解释:你的函数函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。

算法思路

有时候觉得我菜的抠脚,就比如这道题,很明显的双指针,但是我糖了半天,最后虽然过了,但是效率也出奇的低,大致讲一下我的shit思路:

  1. 一个指针i用来指向目标元素val,另一个指针j指向非目标元素
  2. 交换nums[i],nums[j],重复此步骤
  3. 遍历数组,记录val的个数k,返回n-k

最有槽点的其实就是第三步,明明我们在交换的这个步骤中就可以记录val的数量,为啥还要在遍历一次,其实主要是我没解决一个问题:如果测试样例是这样,nums=[1, 1, 1], val = 1,那这样就不需要交换,进而就没办法同步计数val的值,大晚上我也有点懒得解决问题了,就想了个这么低效的办法,最后的代码真是屎山:

cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int i = 0;
int j;
int ans = 0;
int n = nums.size();
int numpfval = 0;
for (auto i : nums) {
numpfval += (i == val) ? 1 : 0;
}
while (i < n) {
while (i < n && nums[i] != val) i++;// 指向val
j = i;
while (j < n && nums[j] == val) j++; // 指向其他元素
if (i < n && j < n) {
swap(nums[i], nums[j]);
}
else {
// 说明j找不到其他的非val元素,交换完成
break;
}
}
return n - numpfval;
}
};

再来看看两个月前我看代码随想录时写的题解,其实类似于快慢指针,真是天壤之别:

cpp
1
2
3
4
5
6
7
8
9
10
11
12
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int n = nums.size(), j = 0;
for (int i = 0; i< n; i++) {
if (nums[i] != val) {
nums[j++] = nums[i];
}
}
return j;
}
};

明显高效的多,乐……