资讯详情

双指针技巧解决LeetCode数组去重问题

📅 2026/10/24 6:29:36 | 华诺云谱 👁 阅读
双指针技巧解决LeetCode数组去重问题
1. 问题背景与核心思路最近在刷LeetCode热门100题时遇到了两个非常经典的数组操作问题删除排序数组中的重复项26题和删除排序数组中的重复项II80题。这两个问题看似简单但想要写出高效且正确的解法需要对双指针技巧有深刻理解。作为数组类问题的经典代表它们经常出现在大厂面试中也是检验基础算法能力的重要标尺。这两个问题的核心要求都是对已排序数组进行原地修改这意味着我们不能使用额外的存储空间必须直接在原数组上进行操作。这种限制条件在实际开发中也很常见比如处理内存受限环境下的数据去重或者优化大数据量的处理性能。2. 基础版删除重复项26题2.1 问题描述给定一个已排序的数组nums要求原地删除重复出现的元素使每个元素只出现一次并返回新数组的长度。要求时间复杂度O(n)空间复杂度O(1)。示例 输入nums [0,0,1,1,1,2,2,3,3,4] 输出5, nums [0,1,2,3,4,...]2.2 双指针解法详解这个问题的标准解法是使用快慢双指针def removeDuplicates(nums): if not nums: return 0 slow 0 for fast in range(1, len(nums)): if nums[fast] ! nums[slow]: slow 1 nums[slow] nums[fast] return slow 1关键点解析初始化时slow和fast指针分别指向0和1fast指针遍历整个数组slow指针标记当前不重复序列的末尾当发现nums[fast] ≠ nums[slow]时说明遇到新元素将slow后移并更新值注意题目不要求删除超出新长度后面的元素所以不需要实际删除多余元素2.3 复杂度分析时间复杂度O(n)只需一次遍历空间复杂度O(1)只使用了常数级别的额外空间3. 进阶版删除重复项II80题3.1 问题升级现在允许每个元素最多出现两次其他条件不变。这是对基础问题的合理扩展也更接近实际业务场景如日志去重时保留最近几条记录。示例 输入nums [1,1,1,2,2,3] 输出5, nums [1,1,2,2,3,...]3.2 解法优化我们需要调整指针移动条件增加出现次数的判断def removeDuplicates(nums): if len(nums) 2: return len(nums) slow 2 for fast in range(2, len(nums)): if nums[fast] ! nums[slow-2]: nums[slow] nums[fast] slow 1 return slow关键改进点初始时slow从2开始前两个元素无论是否重复都保留比较nums[fast]与nums[slow-2]来判断是否超过两次出现通过slow指针构建满足条件的新数组3.3 通用化思考这个问题可以进一步抽象为允许最多k次重复的情况。解法模板如下def removeDuplicatesK(nums, k): if len(nums) k: return len(nums) slow k for fast in range(k, len(nums)): if nums[fast] ! nums[slow-k]: nums[slow] nums[fast] slow 1 return slow4. 常见错误与调试技巧4.1 典型错误案例边界条件处理不足忘记检查空数组或单元素数组指针移动逻辑错误在基础版中错误地比较nums[fast]和nums[fast-1]返回值计算错误忘记slow指针需要1因为从0开始4.2 调试建议使用小规模测试用例手动模拟指针移动打印每次迭代后的数组状态print(ffast{fast}, slow{slow}, nums{nums})特别注意数组前几个元素的处理是否正确5. 实际应用场景5.1 数据库去重操作在大数据ETL过程中经常需要对已排序的时序数据进行去重。例如用户行为日志去重保留最近N条相同操作传感器数据清洗允许一定程度的重复波动5.2 内存优化技巧当处理GB级别的数组时原地算法可以避免创建新数组的内存开销减少GC压力提高缓存命中率数据保持连续6. 扩展练习建议为了巩固双指针技巧推荐尝试以下LeetCode题目移动零283题 - 类似的双指针应用颜色分类75题 - 三指针变体合并两个有序数组88题 - 逆向双指针删除链表中的重复元素83题 - 在链表结构中的应用7. 性能优化进阶对于特别大的数组可以考虑以下优化提前终止当fast指针剩余元素都相同时可提前结束块移动当遇到连续多个重复时可以计算跳跃距离SIMD指令利用现代CPU的并行处理能力在C等语言中8. 不同语言实现要点8.1 C实现注意事项int removeDuplicates(vectorint nums) { if(nums.empty()) return 0; int slow 0; for(int fast1; fastnums.size(); fast){ if(nums[fast] ! nums[slow]){ nums[slow] nums[fast]; } } return slow1; }注意vector的引用传递使用前置提高效率8.2 Java实现特点public int removeDuplicates(int[] nums) { if(nums.length 0) return 0; int slow 0; for(int fast1; fastnums.length; fast){ if(nums[fast] ! nums[slow]){ nums[slow] nums[fast]; } } return slow1; }数组长度用length属性注意参数是int[]而非List9. 测试用例设计完整的测试应该包括空数组 []单元素数组 [1]全相同数组 [2,2,2]无重复数组 [1,2,3]常规案例 [0,0,1,1,1,2,2,3,3,4]边界值 [Integer.MAX_VALUE, Integer.MAX_VALUE]10. 面试考察点分析面试官通常会关注能否正确实现基础算法50%是否考虑边界条件20%能否解释时间/空间复杂度15%能否扩展到变种问题15%在回答时建议先明确问题要求和约束条件举例说明算法流程讨论可能的优化方向主动提及相关的扩展问题11. 个人实战心得在实际刷题和面试过程中我发现这类问题最容易出错的地方在于指针初始化和移动条件。有几个实用技巧先写注释再写代码明确每个指针的职责对于slow指针的更新统一使用前置操作测试时特别关注数组前两个和最后两个元素的处理可以先用额外空间实现再优化为原地算法对于进阶问题我建议先在纸上画出指针移动的示意图。例如对于允许重复两次的情况可以想象有一个观察窗口始终查看slow-2位置的元素这样更容易理解比较逻辑。
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑