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

题意: 给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。 不要使用额外的数组空间,你必须在原地修改输入数组 并在使用 O(1) 额外空间的条件下完成。

题目链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/

视频链接:https://www.bilibili.com/video/BV18G5UzzE8c/

一、看到题目的第一想法

这道题是「有序数组去重,每个元素最多保留两次」,和经典的快慢指针去重题是同类型的变种题。

  1. 核心直觉:因为数组是有序的,重复元素一定是连续的,所以可以用快慢指针来实现「原地修改」,不需要额外空间。
  2. 快慢指针的角色定位
    • fast 指针负责遍历整个数组,寻找符合条件的元素(也就是不会让重复次数超过 2 次的元素)。
    • slow 指针负责维护「有效数组」的末尾位置,记录下一个可以存放新元素的位置。
  3. 边界条件预判:当数组长度 ≤ 2 时,不管元素是否重复,都可以直接返回原长度,因为最多也只有两个元素,天然满足 "不超过两次重复" 的要求。

二、实现过程中遇到的困难

  1. 慢指针起始位置的选择 一开始很容易沿用 "去重保留一次" 的写法,把 slow 初始化为 1。但这道题允许保留两次,前两个元素天然有效,所以 slow 应该从索引 2 开始,直接从第三个元素开始判断是否需要替换。
  2. 判断条件的误区 很容易错误地用 nums[slow-1]nums[fast] 比较,这样会误判 "连续三个相同元素" 的情况。正确的逻辑是:只要 fast 指向的元素,和 slow 维护的有效数组中倒数第二个元素不同,就说明它还没出现过三次,可以加入有效数组 。也就是 nums[slow-2] != nums[fast]
  3. 指针移动的顺序问题 一开始可能会把 ++fast 写在 if 分支里,导致循环中 fast 没有每次都移动,出现死循环或者漏遍历的情况。fast 指针必须在每次循环中都移动,只有满足条件时才移动 slow 指针。
  4. 对 "原地修改" 的理解偏差一开始可能会想着额外开一个数组存结果,忽略了题目要求的「原地修改」和「O (1) 额外空间」限制,而快慢指针刚好能满足这一点。

三、今日收获心得

  1. 快慢指针的通用模板思想 这类「有序数组去重 / 移除指定元素」的题目,快慢指针是通用解法:
    • fast 遍历原数组,筛选有效元素。
    • slow 维护有效数组的写入位置,原地覆盖修改。这道题只是把 "保留一次" 的逻辑改成了 "保留两次",核心框架没有变。
  2. 有序数组的隐藏优势有序数组的重复元素是连续的,这让我们不需要额外的哈希表统计次数,只需要通过和前面固定位置的元素比较,就能判断重复次数,大大优化了空间复杂度。
  3. 边界条件的重要性 一开始处理 numsSize <= 2 的情况,不仅能减少后续循环的无效执行,也避免了数组越界的问题,写算法题时先处理边界条件是个好习惯。
  4. 条件判断的本质理解 这道题的核心条件 nums[slow-2] != nums[fast],本质是在判断「当前元素是否已经在有效数组中出现了两次」,而不是简单的和前一个元素比较。理解了这一点,就可以轻松扩展到 "允许重复 k 次" 的通用场景(只需要把 slow-2 改成 slow-k 即可)。
相关推荐
蝈理塘(/_\)大怨种9 小时前
快速排序的三路划分和自省排序
数据结构·算法
qq_2965532710 小时前
矩阵转置的两种实现方式:从暴力法到原地算法
数据结构·线性代数·算法·青少年编程·矩阵
shylyly_10 小时前
内存函数的使用和实现
数据结构·算法
代码改善世界10 小时前
【C++进阶】二叉搜索树
java·数据结构·c++
如竟没有火炬10 小时前
至少有K个重复字符的最长子串
开发语言·数据结构·python·算法·leetcode·动态规划
不知名的忻12 小时前
堆排序(Java)
java·数据结构·算法·排序算法
shylyly_13 小时前
大小端字节序
数据结构·算法·联合体·大小端字节序·字节序判断
故事和你9113 小时前
洛谷-【图论2-1】树6
开发语言·数据结构·c++·算法·深度优先·动态规划·图论
YL2004042613 小时前
044二叉搜索树中第K小的元素
数据结构·leetcode
图码13 小时前
生命游戏的优雅解法:从O(mn)空间到O(1)空间的进阶之旅
数据结构·算法·游戏·矩阵·空间计算