0027. 移除元素【简单】
1. 📝 题目描述
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。
假设 nums 中不等于 val 的元素数量为 k,要通过此题,您需要执行以下操作:
- 更改
nums数组,使nums的前k个元素包含不等于val的元素。nums的其余元素和nums的大小并不重要。 - 返回
k。
用户评测:
评测机将使用以下代码测试您的解决方案:
txt
int[] nums = [...]; // 输入数组
int val = ...; // 要移除的值
int[] expectedNums = [...]; // 长度正确的预期答案。
// 它以不等于 val 的值排序。
int k = removeElement(nums, val); // 调用你的实现
assert k == expectedNums.length;
sort(nums, 0, k); // 排序 nums 的前 k 个元素
for (int i = 0; i < actualLength; i++) {
assert nums[i] == expectedNums[i];
}1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
如果所有的断言都通过,你的解决方案将会通过。
示例 1:
txt
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2,_,_]1
2
2
解释:
你的函数应该返回 k = 2, 并且 nums 中的前两个元素均为 2。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。
示例 2:
txt
输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3,_,_,_]1
2
2
解释:
你的函数应该返回 k = 5,并且 nums 中的前五个元素为 0, 0, 1, 3, 4。
注意这五个元素可以任意顺序返回。
你在返回的 k 个元素之外留下了什么并不重要(因此它们并不计入评测)。
提示:
0 <= nums.length <= 1000 <= nums[i] <= 500 <= val <= 100
2. 🎯 s.1 - 快慢指针 + 原地覆盖
c
int removeElement(int* nums, int numsSize, int val) {
int slow = 0;
for (int fast = 0; fast < numsSize; fast++) {
if (nums[fast] != val) {
nums[slow++] = nums[fast];
}
}
return slow;
}1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
js
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function (nums, val) {
let slow = 0
for (let fast = 0; fast < nums.length; fast++) {
if (nums[fast] !== val) {
nums[slow++] = nums[fast]
}
}
return slow
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
py
class Solution:
def removeElement(self, nums: list[int], val: int) -> int:
slow = 0
for fast in range(len(nums)):
if nums[fast] != val:
nums[slow] = nums[fast]
slow += 1
return slow1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
- 时间复杂度:
,其中 是数组长度;快指针只需从左到右遍历一次数组,每个元素最多处理一次 - 空间复杂度:
,只使用了快慢指针这几个常数级别的额外变量
算法思路:
- 用慢指针
slow表示“下一个应该写入非val元素的位置”,快指针fast负责从左到右扫描整个数组 - 如果
nums[fast] != val,说明当前元素应该被保留,就把它写到nums[slow],然后将slow向后移动一位 - 如果
nums[fast] == val,说明当前元素需要被移除,直接跳过即可 - 遍历结束后,数组前
slow个元素就是保留下来的结果,返回slow
3. 🎯 s.2 - 双指针 + 尾部覆盖
c
int removeElement(int* nums, int numsSize, int val) {
int left = 0;
int right = numsSize;
while (left < right) {
if (nums[left] == val) {
nums[left] = nums[right - 1];
right--;
} else {
left++;
}
}
return right;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
js
/**
* @param {number[]} nums
* @param {number} val
* @return {number}
*/
var removeElement = function (nums, val) {
let left = 0
let right = nums.length
while (left < right) {
if (nums[left] === val) {
nums[left] = nums[right - 1]
right--
} else {
left++
}
}
return right
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
py
class Solution:
def removeElement(self, nums: list[int], val: int) -> int:
left = 0
right = len(nums)
while left < right:
if nums[left] == val:
nums[left] = nums[right - 1]
right -= 1
else:
left += 1
return right1
2
3
4
5
6
7
8
9
10
11
12
13
2
3
4
5
6
7
8
9
10
11
12
13
- 时间复杂度:
,其中 是数组长度;每次循环要么移动左指针,要么缩短有效区间长度,因此总操作次数是线性的 - 空间复杂度:
,只使用了两个指针变量
算法思路:
- 用
left遍历当前有效区间,用right表示当前有效数组长度,也就是“尾部还剩多少元素可用” - 如果
nums[left] != val,说明当前位置元素可以保留,直接让left向后移动 - 如果
nums[left] == val,就用当前有效区间最后一个元素nums[right - 1]覆盖它,并将right减 1,表示有效区间缩短一位 - 这里覆盖后不能立刻移动
left,因为新换过来的这个元素还没有检查,仍然可能等于val - 当
left == right时,说明所有需要保留的元素都已经被压缩到数组前部,返回left或right即可