删除数组元素方法大揭秘:五大方案纵横leetcode27「移除数组」
2023-10-22 00:29:41
在编程领域,数组是一种常见的数据结构,我们经常需要对数组元素进行各种操作,其中删除元素是一个基本且常用的操作。在本文中,我们将深入探讨一道经典的数组删除元素题目——leetcode27「移除数组」,并提供五种不同的解决方案,帮助你从容应对各种数组元素删除场景。
问题背景
leetcode27「移除数组」题目如下:
给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
方法一:双指针法
双指针法是一种常见的数组元素删除方法,它使用两个指针 i 和 j 来遍历数组。指针 i 指向当前正在检查的元素,而指针 j 指向下一个未被删除的元素。当 i 指向一个等于 val 的元素时,我们将其跳过,继续检查下一个元素。当 i 指向一个不等于 val 的元素时,我们将该元素的值复制到 j 指向的位置,并更新 j 的值。这样,我们就将等于 val 的元素从数组中删除,同时保持数组的顺序不变。
int removeElement(vector<int>& nums, int val) {
int i = 0;
int j = 0;
while (i < nums.size()) {
if (nums[i] != val) {
nums[j] = nums[i];
j++;
}
i++;
}
return j;
}
public int removeElement(int[] nums, int val) {
int i = 0;
int j = 0;
while (i < nums.length) {
if (nums[i] != val) {
nums[j] = nums[i];
j++;
}
i++;
}
return j;
}
方法二:逆向双指针法
逆向双指针法与双指针法类似,但它使用两个指针 i 和 j 从数组的尾部开始遍历。指针 i 指向当前正在检查的元素,而指针 j 指向下一个未被删除的元素。当 i 指向一个等于 val 的元素时,我们将其跳过,继续检查上一个元素。当 i 指向一个不等于 val 的元素时,我们将该元素的值复制到 j 指向的位置,并更新 j 的值。这样,我们就将等于 val 的元素从数组中删除,同时保持数组的顺序不变。
int removeElement(vector<int>& nums, int val) {
int i = nums.size() - 1;
int j = nums.size() - 1;
while (i >= 0) {
if (nums[i] != val) {
nums[j] = nums[i];
j--;
}
i--;
}
return j + 1;
}
public int removeElement(int[] nums, int val) {
int i = nums.length - 1;
int j = nums.length - 1;
while (i >= 0) {
if (nums[i] != val) {
nums[j] = nums[i];
j--;
}
i--;
}
return j + 1;
}
方法三:替换法
替换法是一种简单而有效的数组元素删除方法。它使用一个指针 i 来遍历数组。当 i 指向一个等于 val 的元素时,我们将该元素的值替换为数组中最后一个元素的值,然后将最后一个元素的值设置为 val。这样,我们就将等于 val 的元素从数组中删除,同时保持数组的顺序不变。
int removeElement(vector<int>& nums, int val) {
int i = 0;
while (i < nums.size()) {
if (nums[i] == val) {
nums[i] = nums[nums.size() - 1];
nums.pop_back();
} else {
i++;
}
}
return nums.size();
}
public int removeElement(int[] nums, int val) {
int i = 0;
while (i < nums.length) {
if (nums[i] == val) {
nums[i] = nums[nums.length - 1];
nums = Arrays.copyOf(nums, nums.length - 1);
} else {
i++;
}
}
return nums.length;
}
方法四:位操作法
位操作法是一种巧妙的数组元素删除方法。它使用一个掩码来标记需要删除的元素。掩码是一个与数组长度相等的数组,其中每个元素的值为 1 或 0。如果一个元素需要被删除,则其对应的掩码元素值为 1,否则为 0。然后,我们可以使用掩码来过滤掉需要删除的元素,并将剩余元素复制到一个新的数组中。
int removeElement(vector<int>& nums, int val) {
vector<int> mask(nums.size(), 0);
for (int i = 0; i < nums.size(); i++) {
if (nums[i] == val) {
mask[i] = 1;
}
}
int j = 0;
for (int i = 0; i < nums.size(); i++) {
if (mask[i] == 0) {
nums[j] = nums[i];
j++;
}
}
return j;
}
public int removeElement(int[] nums, int val) {
int[] mask = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
if (nums[i] == val) {
mask[i] = 1;
}
}
int j = 0;
for (int i = 0; i < nums.length; i++) {
if (mask[i] == 0) {
nums[j] = nums[i];
j++;
}
}
return j;
}
方法五:标准库函数法
标准库函数法是一种简单易用的数组元素删除方法。它使用标准库函数 std::remove
或 std::remove_if
来删除等于 val 的元素。
int removeElement(vector<int>& nums, int val) {
auto it = std::remove(nums.begin(), nums.end(), val);
nums.erase(it, nums.end());
return nums.size();
}
public int removeElement(int[] nums, int val) {
int[] result = Arrays.stream(nums).filter(n -> n != val).toArray();
return result.length;
}
性能分析
以下是五种方法的时间复杂度和空间复杂度分析:
方法 | 时间复杂度 | 空间复杂度 |
---|---|---|
双指针法 | O(n) | O(1) |
逆向双指针法 | O(n) | O(1) |
替换法 | O(n) | O(1) |
位操作法 | O(n) | O(n) |
标准库函数法 | O(n) | O(1) |
其中,n 为数组的长度。
总结
在本文中,我们介绍了五种删除数组元素的方法,包括双指针法、逆向双指针法、替换法、位操作法和标准库函数法。每种方法都有其优缺点,在不同的场景下可能会有不同的表现。开发者可以根据具体需求选择合适的方法来删除数组元素。