当前位置: 首页 > news >正文

leetcode80:删除有序数组中的重复项 II(快慢指针法)

文章目录

  • 一、 题目描述
  • 二、 核心思路:快慢指针
  • 三、计数器辅助的快慢指针
    • 代码实现-直观快慢指针
    • 优缺点分析
  • 四、 深度拓展:更通用的快慢指针模板
    • 核心思想
    • 代码实现-通用模板
    • 优缺点分析
  • 五、 总结

LeetCode 80 删除有序数组中的重复项 II,【难度:中等;通过率:63.5%】,这道题是 LeetCode 26 删除有序数组中的重复项 的进阶版,要求我们保留最多 两个重复的元素,同样可是接着使用 双指针-快慢指针法解决,并且我们通过此题,总结出一个 通用的模板,最终可以解决 删除有序数组中的重复 K 项的问题

一、 题目描述

给你一个有序数组 nums,请你原地删除重复出现的元素,使得每个元素最多出现两次,返回删除后数组的新长度

不要使用额外的数组空间,你必须在 原地 修改输入数组并在使用 O(1) 额外空间的条件下完成

示例:

输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3,_]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3

二、 核心思路:快慢指针

解决此类问题的核心武器是快慢指针。我们将数组逻辑上分为两部分:

  • [0...slow-1]:这是我们处理好的、满足“最多重复两次”要求的新数组
  • [slow...fast-1]:这是已经被 fast 指针扫描过,但被我们“抛弃”的元素
  • [fast...n-1]:这是待探索的未知区域

指针职责:

  • slow (慢指针):作为“写入”指针,nums[slow] 是下一个将被覆盖的位置。slow 本身也代表了新数组的长度
  • fast (快指针):作为“读取”指针,nums[fast] 是当前正在考察的元素

我们的目标就是移动 fast 指针遍历整个数组,当遇到一个“合法”的元素时,就将它“写入”到 slow 指针的位置,然后 slow 前进一格


三、计数器辅助的快慢指针

一种非常直观的实现思路:通过一个额外的计数器来判断当前元素是否“合法”

代码实现-直观快慢指针

class Solution {/*** 使用快慢指针,并辅以一个 repeat 计数器来跟踪当前元素的重复次数* slow 指针永远指向下一个可以被覆盖的位置*/public int removeDuplicates(int[] nums) {if (nums.length <= 2) {return nums.length;}int slow = 1; // 新数组的构建从索引 1 开始int repeat = 1; // 记录当前元素的重复次数for (int fast = 1; fast < nums.length; fast++) {// 遇到重复元素if (nums[fast] == nums[fast - 1]) {repeat++;// 如果重复次数小于等于 2,则保留该元素if (repeat <= 2) {nums[slow++] = nums[fast];}// 如果 repeat > 2,则不移动 slow,fast 继续前进,相当于“跳过”了该元素} else { // 遇到新元素repeat = 1; // 重置计数器nums[slow++] = nums[fast]; // 保留新元素}}return slow;}
}

提交结果:

在这里插入图片描述

优缺点分析

  • 优点:逻辑非常清晰易懂,通过 repeat 计数器,我们能准确地知道每个元素的重复情况,易于理解和调试

四、 深度拓展:更通用的快慢指针模板

我们甚至可以摆脱 repeat 计数器,让逻辑更简洁,也更具扩展性,总结出一个此类题通用模板

核心思想

我们换一个角度思考:fast 指针指向的元素 nums[fast] 什么时候应该被保留?

答案是:当 nums[fast] 与新数组 [0...slow-1] 的倒数第二个元素 nums[slow-2] 不相等

为什么是 slow-2

  • nums[slow-1] 是新数组的最后一个元素
  • nums[slow-2] 是新数组的倒数第二个元素
  • 如果 nums[fast]nums[slow-2] 相等,那么 nums[slow-1] 必然也和它们相等,因为:数组有序(题目给的条件),即 nums[fast] 将是第三个重复的元素,应该被抛弃
  • 反之,如果 nums[fast]nums[slow-2] 不相等,那么 nums[fast] 最多只是第二个重复的元素,应该被保留

我们还需要处理一个边界情况:当 slow < 2 时,新数组的长度还不足 2,此时任何元素都应该被无条件保留

代码实现-通用模板

class Solution {public int removeDuplicates(int[] nums) {if (nums.length <= 2) {return nums.length;}int slow = 2; // 新数组的前两个元素 [0, 1] 默认保留for (int fast = 2; fast < nums.length; fast++) {// 检查 fast 指向的元素是否应该被保留// 如果 nums[fast] 不等于新数组的倒数第二个元素 nums[slow-2]// 说明 nums[fast] 不是第三个重复元素,可以保留if (nums[fast] != nums[slow - 2]) {nums[slow] = nums[fast];slow++;}}return slow;}
}

提交结果:

在这里插入图片描述

优缺点分析

  • 优点
    • 代码更简洁,没有额外的状态变量
    • 扩展性极强:如果题目改成“最多保留 k 个重复项”,我们只需将 2 替换为 k 即可:if (slow < k || nums[fast] != nums[slow - k])。这是一个非常强大的通用模板
  • 缺点:逻辑相对抽象,需要深刻理解 slow-2 的含义,以及为什么可以这样:题目说是有序

五、 总结

解法一 (计数器辅助)解法二 (通用模板)
核心逻辑通过 repeat 计数器判断是否保留通过与 nums[slow-2] 比较来判断是否保留
状态变量slow, fast, repeatslow, fast
代码简洁性中等
扩展性需要修改 repeat <= 2 的判断只需将 2 替换为 k 即可
时间/空间复杂度O(N) / O(1)O(N) / O(1)
http://www.xdnf.cn/news/1352755.html

相关文章:

  • 日语学习-日语知识点小记-进阶-JLPT-N1阶段蓝宝书,共120语法(6):51-60语法
  • Day33 MLP神经网络的训练
  • 「ECG信号处理——(24)基于ECG和EEG信号的多模态融合疲劳分析」2025年8月23日
  • 前端 H5分片上传 vue实现大文件
  • 【卫星通信】超低码率语音编码ULBC:EnCodec神经音频编解码器架构深度解析
  • piclist+gitee操作指南
  • 【Day 11】238.除自身以外数组的乘积
  • Transformer核心概念I-token
  • SpringBoot 快速上手:从环境搭建到 HelloWorld 实战
  • Excel 条件高亮工具,秒高亮显示符合筛选条件的行数据
  • 「数据获取」《中国能源统计年鉴》(1986-2023)(获取方式看绑定的资源)
  • 蓝桥杯算法之基础知识(2)——Python赛道
  • 【51单片机学习】直流电机驱动(PWM)、AD/DA、红外遥控(外部中断)
  • mmdetection:记录算法训练配置文件
  • A Large Scale Synthetic Graph Dataset Generation Framework的学习笔记
  • Mysql EXPLAIN详解:从底层原理到性能优化实战
  • 如何在Ubuntu中删除或修改已有的IP地址设置?
  • C语言---数据类型
  • PyTorch生成式人工智能——VQ-VAE详解与实现
  • TypeScript 的泛型(Generics)作用理解
  • Kafka 概念与概述
  • 在TencentOS3上部署OpenTenBase:从入门到实战的完整指南
  • 【Java学习笔记】18.反射与注解的应用
  • 遥感机器学习入门实战教程|Sklearn案例⑧:评估指标(metrics)全解析
  • tcpdump命令打印抓包信息
  • 【golang】ORM框架操作数据库
  • 2-5.Python 编码基础 - 键盘输入
  • STM32CubeIDE V1.9.0下载资源链接
  • 醋酸镨:催化剂领域的璀璨新星
  • LangChain4J-基础(整合Spring、RAG、MCP、向量数据库、提示词、流式输出)