面试算法题之移除元素

移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

双指针

对于要求原地实现移除,我们可以使用双指针的方式实现。

首先我们定义 lr两个指针,r指针指向当前需要处理的元素,l指针则指向要被覆盖的元素,即新数组的尾部。遍历数组,当r指针指向的元素与val不相等时,则将r指针指向的元素移动到l指针指向的数组下标,并将lr两个指针向后移动一位;否则只移动r指针。

最后,l指针指向的下标就是新数组的尾部,根据题意,直接放回l 即可。

ini 复制代码
```cpp
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int n = nums.size(), l = 0, r = 0;
        for(; r < n; r++) {
            if(nums[r] != val) {
                nums[l] = nums[r];
                l++;
            }
        }
        return l;
    }
};

进一步优化,如果我们要移除的元素恰好在数组的头部,此时需要把每一个元素都左移一位,这样比较费时。根据题意,新数组的元素的排序是可以改更改的。这样我们就可以直接将数组中的最后一个元素移动到数组头部,如此也是满足题目的要求。

cpp 复制代码
class Solution {
public:
    int removeElement(vector<int>& nums, int val) {
        int l = 0, r = nums.size();
        while(l < r) {
            if(nums[l] == val) {
                nums[l] = nums[r - 1];
                r--;
            } else {
                l++;
            }
        }
        return l;
    }
};

删除有序数组中的重复项

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k

判题标准:

系统会用下面的代码来测试你的题解:

ini 复制代码
int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过

双指针

这题同样可以使用双指针实现,因为题意说明数组是有序的,即重复的元素一定是相邻的。

我们定义 lr两个指针,r指针指向当前需要处理的元素,l指针则指向要被覆盖的元素,即新数组的尾部。遍历数组,当r指针指向的元素与l指针指向元素不相等时,则将r指针指向的元素移动到l指针指向的数组下一位,并将lr两个指针向后移动一位;否则只移动r指针。最后l+1即是新数组的长度。

cpp 复制代码
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        if(n == 0) return 0;
        int l = 0, r = 0;
        for(; r < n; r++) {
            if(nums[l] != nums[r]) {
                nums[++l] = nums[r];
            }
        }
        return l + 1;
    }
};

思考

  1. 若给出的数组不是有序的呢?该如何实现

删除有序数组中的重复项 II

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以**「引用」**方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

go 复制代码
// **nums** 是以"引用"方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 **该长度范围内** 的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}

双指针

跟上一题一样,不同的是相同的元素可以保留两位。

同样可以使用双指针实现,只需要稍微改动一下。

首先,数组长度在2及2以下的都可以满足条件。对于超过2的,我们定义lr两个指针,r指针指向当前需要处理的元素,l指针则指向要被覆盖的元素,即新数组的尾部。遍历数组,当r指针指向的元素与l-2指针指向的元素不相等时(刚好满足保留两位相同数的要求),则将r指针指向的元素移动到l指针指向的数组下标,并将lr两个指针向后移动一位;否则只移动r指针。最后,新数组的长度为l,根据题意放回l即可。

cpp 复制代码
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        if (n <= 2) return n;
        int l = 2, r = 2;
        for(; r < n; r++) {
            if(nums[l - 2] != nums[r]) {
                nums[l++] = nums[r];
            }
        }
        return l;
    }
};
相关推荐
鱼跃鹰飞9 小时前
Leetcode面试经典150题-349.两个数组的交集
算法·leetcode·面试
程序猿进阶15 小时前
如何在 Visual Studio Code 中反编译具有正确行号的 Java 类?
java·ide·vscode·算法·面试·职场和发展·架构
无名之逆16 小时前
云原生(Cloud Native)
开发语言·c++·算法·云原生·面试·职场和发展·大学期末
andrew_121920 小时前
腾讯 IEG 游戏前沿技术 一面复盘
java·redis·sql·面试
andrew_121920 小时前
腾讯 IEG 游戏前沿技术 二面复盘
后端·sql·面试
寻求出路的程序媛20 小时前
JVM —— 类加载器的分类,双亲委派机制
java·jvm·面试
kay_54521 小时前
YOLOv8改进 | 模块缝合 | C2f 融合SCConv提升检测性能【CVPR2023】
人工智能·python·深度学习·yolo·目标检测·面试·yolov8改进
gopher95111 天前
qt相关面试题
开发语言·qt·面试
视觉小鸟1 天前
【java面试每日五题之基础篇一】(仅个人理解)
java·笔记·面试
vd_vd1 天前
内存区域-面试与分析
jvm·面试·职场和发展