双指针适合有序数组去重,因重复元素必然相邻,无需哈希表或splice;快指针遍历,慢指针定位唯一值位置,时间o(n)、空间o(1),原地修改并返回有效长度。

JavaScript 中用双指针实现有序数组去重,核心是利用数组已排序的特性,只遍历一次、不新建数组、空间复杂度 O(1),且真正满足“原地修改”要求——即复用原数组内存,仅通过调整有效长度界定结果。
为什么双指针适合有序数组去重
因为重复元素必然相邻。不需要哈希表查重,也不需要反复 splice 删除;只需比较当前元素和前一个已保留元素是否不同,就能判断是否该保留。快指针扫全数组,慢指针只记录唯一值应落的位置。
标准双指针实现(保留每个元素一次)
适用于 LeetCode 26 类题目,输入如 [0,0,1,1,1,2,2,3,3,4],输出有效长度 5,原数组前 5 位变为 [0,1,2,3,4]:
- 慢指针 slow 初始为 0,指向第一个元素(它一定保留)
- 快指针 fast 从索引 1 开始遍历
- 若 nums[fast] !== nums[slow],说明遇到新值:先 slow++,再赋值 nums[slow] = nums[fast]
- 循环结束后,slow + 1 就是去重后有效长度
- 如需截断数组,可加 nums.length = slow + 1
扩展:保留最多两个相同元素(LeetCode 80)
当允许每个数最多出现两次时,逻辑稍变:慢指针初始设为 1(前两个位置默认可用),判断依据改为与 nums[slow - 1] 比较:
- 如果 nums[fast] !== nums[slow - 1],说明当前值在已保留段中最多只出现了一次,可以再放一次
- 此时执行 slow++ 并赋值
- 这样能确保任意连续三个位置不会全相同
注意事项与常见误区
双指针法不适用于无序数组——必须先排序,否则无法保证重复项相邻,会导致漏删或误删。
- 不要在循环中用 splice 配合双指针:虽然能“视觉上”删掉元素,但每次 splice 都会移动后续元素,时间复杂度退化到 O(n²)
- 返回的是长度,不是新数组;调用方需用 nums.slice(0, len) 获取结果,或主动截断 nums.length = len
- 空数组或单元素数组要单独处理,避免 fast 越界
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











