LeetCode 27 移除元素

1. 题目

27. 移除元素 - 力扣(LeetCode)

题目描述

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

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

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

示例

输入:nums = 3,2,2,3, val = 3

输出:2, nums = 2,2,*,*

输入:nums = 0,1,2,2,3,0,4,2, val = 2

输出:5, nums = 0,1,4,0,3,*,*,_

约束

  • (0 <= nums.length <= 100)

  • (0 <= numsi <= 50)

  • (0 <= val <= 100)

2. 最佳解题思路描述(快慢双指针,本题标准最优)

  1. 定义快慢指针:

    • fast 快指针:遍历整个数组,逐个检查当前元素;

    • slow 慢指针:指向有效数组待填充位置,记录不等于 val 的元素存放下标;

  2. 遍历逻辑:

    • nums[fast] != val:说明是保留元素,把值赋给 nums[slow],慢指针后移;

    • 若等于 val:直接跳过,慢指针不动;

  3. 遍历结束后,slow 的数值就是新数组长度,直接返回。

优势

  • 时间复杂度 (O(n)):仅一次遍历数组;

  • 空间复杂度 (O(1)):仅两个临时变量,原地修改,无额外容器;

  • 代码极简、逻辑清晰,是数组原地去重 / 移除指定值通用模板。

3. 我的可优化代码(当前代码无逻辑错误,是标准最优解,仅补充优化小细节)

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

代码说明

  1. 正确性:代码逻辑完全正确,能通过全部测试用例,属于本题最优写法,无逻辑 bug;

  2. 可优化小细节(不影响 AC,仅优化拷贝操作):

    当前写法存在不必要赋值:当 slow == fast 时(前面没有待删除元素),nums[slow] = nums[fast] 是自身赋值,可加判断跳过:

    复制代码
    if (val != nums[fast]) {
        if(slow != fast) nums[slow] = nums[fast];
        slow++;
    }

    数组全为保留元素时减少重复赋值,性能微提升。

4. 最优标准代码(你原版,行业通用最简版)

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

5. 总结

  1. 快慢双指针是原地移除元素核心模板,本题代码无错误、效率最优,面试直接写;

  2. 核心规则:快指针负责检索,慢指针负责维护有效数组;

  3. 返回值是慢指针最终数值,不需要额外计算长度;

  4. 题目不要求尾部元素清零,无需额外操作。

6. 相关知识拓展

拓展 1:同类快慢指针数组题型模板

  • LeetCode 26 删除有序数组重复项、LeetCode 283 移动零,完全复用快慢指针思想:

    快指针遍历筛选有效元素,慢指针存放结果。

拓展 2:另一种解法(首尾双指针,适合删除元素很多的场景)

左右指针,左找待删除值、右找保留值,交换后收缩区间,减少数组赋值次数:

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

特点:会打乱数组原有顺序,题目允许顺序改变时可用。

拓展 3:复杂度对比

  1. 快慢指针(你的写法):(O(n)) 时间,(O(1)) 空间,保留原数组顺序;

  2. 首尾交换双指针:(O(n)) 时间,(O(1)) 空间,数组顺序打乱;

  3. 暴力 erase:嵌套循环 erase,(O(n^2)) 时间,效率极低,不推荐面试。

拓展 4:快慢指针通用记忆口诀

快指针全遍历,慢指针存有效;

不等目标就留存,慢指针自增记长度。

相关推荐
冻柠檬飞冰走茶2 小时前
PTA基础编程题目集 7-15 计算圆周率(C语言实现)
c语言·开发语言·数据结构·算法
问商十三载2 小时前
AI 引擎生成式优化两种思路怎么选?2026 对比分析附选型方法
人工智能·算法
hanlin033 小时前
刷题笔记:力扣第704、977、209题(数组相关)
笔记·算法·leetcode
陕西企来客3 小时前
生成式引擎优化(GEO)行业白皮书:从流量分配到认知占有的战略跃迁
人工智能·算法·机器学习·技术好geo优化
清泓y4 小时前
深度学习算法
算法·ai·语言模型·面试
m沐沐4 小时前
【深度学习】循环神经网络RNN——结构、原理与长期依赖问题解析
人工智能·pytorch·python·rnn·深度学习·算法·机器学习
Rabitebla4 小时前
C++ 内存管理全面复习:从内存分布到 operator new/delete
java·c语言·开发语言·c++·算法·leetcode
玖玥拾4 小时前
LeetCode 58 最后一个单词的长度
算法·leetcode