leetcode 27题要求原地移除数组中所有等于val的元素并返回新长度,必须使用快慢指针法:慢指针指向重构后数组末尾,快指针遍历找非val元素,遇非val则赋值并移动慢指针,时间复杂度o(n),空间复杂度o(1)。

快慢指针是解决一维数组原地去重最直接、最高效的方法,尤其适用于已排序数组。它不依赖额外空间,只用一次遍历,时间复杂度 O(n),空间复杂度 O(1),完全满足企业面试对“原地修改”和“最优性能”的双重要求。
为什么必须用快慢指针?
因为题目限制太紧:不能新建数组、不能用哈希表、不能改变元素相对顺序。暴力法(比如每遇到一个数就往前查是否出现过)会退化到 O(n²);排序法在已排好序的前提下纯属多余;而快慢指针天然适配“有序+相邻重复”这一关键特性——重复元素一定挤在一起,所以只需比对相邻值或与已确认的最后一个值比较。
核心角色分工要记牢
慢指针(slow):始终指向已去重区域的末尾位置,也就是下一个合法元素该落脚的地方。
快指针(fast):负责从左到右扫描整个数组,充当“探路者”,只管找新值,不负责安置。
- 初始时 slow = 0,表示 nums[0] 天然唯一,直接保留在原位
- fast 从 1 开始(避免越界),每次比较 nums[fast] 和 nums[slow]
- 一旦发现 nums[fast] ≠ nums[slow],说明是新元素 → 把它挪到 slow+1 位置,然后 slow++
代码写法与关键细节
标准模板如下(Java/Python 逻辑一致):
int slow = 0;
for (int fast = 1; fast
if (nums[fast] != nums[slow]) {
slow++;
nums[slow] = nums[fast];
}
}
return slow + 1;
- 判断条件用 nums[fast] != nums[slow],不是 nums[fast] != nums[fast-1] ——后者虽等价,但前者更通用,容易迁移到“移除指定值”等变体题
- 赋值必须在 slow++ 之后,否则会覆盖掉第一个元素
- 返回值是 slow + 1,因为 slow 是下标,长度要加 1
- 无需清空后半段,题目只要求前 k 个有效,其余可忽略
怎么应对常见变体题?
快慢指针框架不变,只改判断逻辑:
- 移除所有等于 val 的元素(LeetCode 27):把 if 条件换成 nums[fast] != val,其余结构完全一致
- 每个元素最多保留两次(LeetCode 80):slow 不再代表“最后一个不同值”,而是“当前已存元素的末尾”,需额外判断 nums[slow-1] 和 nums[slow] 是否都等于 nums[fast]
- 未排序数组去重:快慢指针失效,必须先排序,或改用哈希集合(但违反原地要求)











