27.Remove Element 移除元素
题目简要介绍
“移除元素” 是LeetCode上难度为简单的题目。给定一个数组 nums 和一个值 val,要求在原数组上移除所有等于 val 的元素,并返回移除后数组的新长度。原数组中剩余元素的顺序可以改变,超出新长度部分的元素无需关心。
各语言实现
Python实现
class Solution:
def removeElement(self, nums, val):
left, right = 0, len(nums) - 1
while left <= right:
if nums[left] == val:
nums[left] = nums[right]
right -= 1
else:
left += 1
return left
Java实现
class Solution {
public int removeElement(int[] nums, int val) {
int left = 0;
int right = nums.length - 1;
while (left <= right) {
if (nums[left] == val) {
nums[left] = nums[right];
right--;
} else {
left++;
}
}
return left;
}
}
C实现
#include <stdio.h>
int removeElement(int* nums, int numsSize, int val) {
int left = 0;
int right = numsSize - 1;
while (left <= right) {
if (nums[left] == val) {
nums[left] = nums[right];
right--;
} else {
left++;
}
}
return left;
}
C++实现
#include <vector>
class Solution {
public:
int removeElement(std::vector<int>& nums, int val) {
int left = 0;
int right = nums.size() - 1;
while (left <= right) {
if (nums[left] == val) {
nums[left] = nums[right];
right--;
} else {
left++;
}
}
return left;
}
};
Go实现
package main
import "fmt"
func removeElement(nums []int, val int) int {
left, right := 0, len(nums)-1
for left <= right {
if nums[left] == val {
nums[left] = nums[right]
right--
} else {
left++
}
}
return left
}
算法复杂性分析
- 时间复杂度:所有实现的时间复杂度均为 O(n)O(n)O(n),其中
n是数组的长度。因为在最坏情况下,需要遍历数组一次,对每个元素进行最多一次比较和可能的一次交换操作。 - 空间复杂度:空间复杂度为 O(1)O(1)O(1),因为都是在原数组上进行操作,没有使用额外的与数组规模相关的空间。
常用解法
- 双指针法:
- 使用两个指针,一个指针
left从数组头部开始,另一个指针right从数组尾部开始。 - 当
left指向的元素等于val时,将right指向的元素与left指向的元素交换,然后right指针左移;当left指向的元素不等于val时,left指针右移。 - 持续这个过程,直到
left大于right,此时left的值就是移除val后数组的新长度。
- 使用两个指针,一个指针
- 记录起始位置法:
- 使用一个变量
begin记录已经确定不包含val的数组范围的末尾位置。 - 通过遍历数组,当遇到不等于
val的元素时,将其赋值到begin位置,然后begin自增。 - 遍历结束后,
begin的值就是移除val后数组的新长度。
- 使用一个变量
实现的关键点和难度
- 关键点:
- 指针的正确移动和元素交换:在双指针法中,准确判断指针指向元素与
val的关系,从而正确移动指针和进行元素交换。例如在Java实现中,if (nums[left] == val)这个判断条件决定了指针的移动和交换逻辑。 - 边界条件处理:确保在遍历数组过程中,指针不会越界。例如在所有语言实现中,
while (left <= right)这个循环条件保证了指针在数组范围内操作。
- 指针的正确移动和元素交换:在双指针法中,准确判断指针指向元素与
- 难度:
- 逻辑清晰性:虽然算法思路相对直接,但在实现过程中要确保指针移动、元素交换等逻辑的正确性,特别是不同指针移动条件的处理,需要清晰的逻辑思维,否则容易出现指针越界或元素处理错误。
- 代码简洁性与可读性:在实现过程中,要在保证代码逻辑正确的前提下,尽量使代码简洁且易读。例如,在不同语言实现中,需要合理组织代码结构,使双指针的操作逻辑一目了然。
扩展及难度加深题目
- 扩展题目:
- 移除数组中所有值在某个区间内的元素:给定一个数组和一个区间
[a, b],移除数组中所有值在该区间内的元素。这需要在遍历数组时,判断元素是否在给定区间内,然后采用类似的双指针或记录起始位置的方法进行移除操作。 - 移除数组中出现次数为特定值的元素:给定一个数组和一个整数
k,移除数组中出现次数恰好为k的元素。这需要先统计每个元素出现的次数,然后再进行移除操作,可以结合哈希表来统计元素出现次数,再用双指针或其他合适方法移除目标元素。
- 移除数组中所有值在某个区间内的元素:给定一个数组和一个区间
- 难度加深题目:
- 在高并发环境下移除数组元素:在多线程环境中,多个线程同时访问和修改数组,需要考虑线程安全问题,例如使用锁机制或原子操作来保证数据的一致性。
- 处理超大数组的移除元素操作:当数组非常大,无法一次性加载到内存中时,需要考虑如何分块处理数组,并且在合并分块数据时保证移除元素的正确性。这涉及到外存数据处理和数据合并的相关知识。
应用场合
- 数据清洗:在数据分析中,可能会遇到需要从数据集中移除特定异常值的情况。例如,在处理用户年龄数据时,如果存在明显错误的年龄值(如负数或过大的不合理值),可以使用此算法移除这些异常数据。
- 游戏开发:在游戏中,当需要移除特定状态或类型的游戏对象时,可以使用这种原地移除的方法。例如,在一个射击游戏中,移除所有被击中的敌人对象。
- 资源管理:在资源分配系统中,若需要移除特定类型或状态的资源,可以借鉴此算法。例如,在内存管理中,移除所有已释放的内存块引用。


1万+

被折叠的 条评论
为什么被折叠?



