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

LeetCode 面试经典 150 题:删除有序数组中的重复项(双指针思想解法详解)

在数组类算法题中,“删除有序数组中的重复项” 是一道高频基础题,它不仅考察对数组 “原地操作” 的掌握,更能体现对 “双指针” 核心思想的理解。由于数组是有序的,重复元素必然相邻,这一特性为我们提供了高效解题的关键突破口。本文将从题目解读到思路推导,再到代码实现,帮你彻底掌握这道题的最优解法。

一、题目链接与题干解读

首先,你可以通过以下链接直接访问题目,先自行思考解题方向:

LeetCode 题目链接:26.删除有序数组中的重复项

题干核心信息

题目要求如下:

给你一个非严格递增排列的数组 nums,请你原地删除重复出现的元素,使每个元素只出现一次,返回删除后数组的新长度。元素的相对顺序应该保持一致

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果,且这些元素的相对顺序和原数组一致。

不需要考虑数组中超出新长度后面的元素。

示例理解

通过两个典型示例,能更直观地理解题目要求:

  • 示例 1:输入 nums = [1,1,2],输出 2,且删除后数组前 2 个元素为 [1,2]。解释:数组是有序的,重复元素 “1” 相邻,删除后保留一个 “1” 和 “2”,新长度为 2。
  • 示例 2:输入 nums = [0,0,1,1,1,2,2,3,3,4],输出 5,且删除后数组前 5 个元素为 [0,1,2,3,4]。解释:重复元素均相邻,删除后每个元素只留一个,新长度为 5。

二、解题思路:用变量 k 记录已处理数组长度

由于数组是有序的,重复元素必然相邻,这意味着我们只需判断 “当前元素是否与已处理部分的最后一个元素相同”—— 若不同,则是新的有效元素,需保留;若相同,则是重复元素,需跳过。

这里的变量k扮演了两个关键角色:

  1. 已处理数组的长度:k的值代表当前已筛选出的 “无重复有效元素” 的个数;
  1. 有效元素的存放位置:数组前k个位置是已处理的无重复区域,下一个有效元素需放到nums[k]的位置。

整个解题逻辑可概括为:从左到右遍历数组,用k维护无重复区域,每遇到与无重复区域最后一个元素不同的元素,就将其加入无重复区域,同时更新k;遇到重复元素则直接跳过

1. 步骤拆解与示例演示

以示例 2(nums = [0,0,1,1,1,2,2,3,3,4])为例,一步步拆解整个过程:

步骤 1:初始化变量 k

初始时,已处理的无重复数组为空,因此k = 0(此时nums的前k=0个元素为空,无重复区域尚未有元素)。

步骤 2:遍历数组,筛选无重复元素

遍历数组的每个元素x(从索引 0 开始),核心判断条件是:k == 0(无重复区域为空,当前元素必然是第一个有效元素)或 x != nums[k-1](当前元素与无重复区域的最后一个元素不同,是新的有效元素)。

具体遍历过程如下:

  • 索引 0:x = 0,此时k = 0(无重复区域为空)→ 符合条件,将0放到nums[0](本身就在正确位置),k自增 1 → k = 1;
  • 索引 1:x = 0,此时k = 1,nums[k-1] = nums[0] = 0 → x == nums[k-1](重复元素),跳过,k保持 1;
  • 索引 2:x = 1,nums[k-1] = 0 → x != nums[k-1](新有效元素),将1放到nums[1](此时nums变为[0,1,1,1,1,2,2,3,3,4]),k自增 1 → k = 2;
  • 索引 3:x = 1,nums[k-1] = 1 → 重复元素,跳过,k保持 2;
  • 索引 4:x = 1,nums[k-1] = 1 → 重复元素,跳过,k保持 2;
  • 索引 5:x = 2,nums[k-1] = 1 → 新有效元素,将2放到nums[2](nums变为[0,1,2,1,1,2,2,3,3,4]),k自增 1 → k = 3;
  • 索引 6:x = 2,nums[k-1] = 2 → 重复元素,跳过,k保持 3;
  • 索引 7:x = 3,nums[k-1] = 2 → 新有效元素,将3放到nums[3](nums变为[0,1,2,3,1,2,2,3,3,4]),k自增 1 → k = 4;
  • 索引 8:x = 3,nums[k-1] = 3 → 重复元素,跳过,k保持 4;
  • 索引 9:x = 4,nums[k-1] = 3 → 新有效元素,将4放到nums[4](nums变为[0,1,2,3,4,2,2,3,3,4]),k自增 1 → k = 5。
步骤 3:返回 k 的值

遍历结束后,k = 5,这就是删除重复项后数组的新长度。此时nums的前 5 个元素[0,1,2,3,4]就是无重复的有效元素,与示例预期结果完全一致。

2. 关键注意点

  • 依赖数组有序性:该解法的前提是数组 “非严格递增”,重复元素必然相邻 —— 若数组无序,此方法不成立(需先排序,但会改变元素相对顺序,不符合题目要求);
  • 原地修改:所有操作都在原数组nums上进行,未开辟新数组,符合题目 “原地操作” 和 “O (1) 额外空间” 的要求;
  • 元素相对顺序不变:有效元素的存放顺序与原数组中首次出现的顺序一致(如示例 2 中,0、1、2、3、4 的顺序与原数组中首次出现的顺序相同),满足题目 “相对顺序一致” 的要求;
  • 无需处理后续元素:题目明确 “不需要考虑数组中超出新长度后面的元素”,因此遍历结束后,无需修改nums[k]及之后的元素,直接返回k即可。

三、复杂度分析

1. 时间复杂度:O (n)

  • 我们只对数组nums进行了一次遍历,每个元素只被判断一次(是否为有效元素),最多执行一次赋值操作(将有效元素放到nums[k]);
  • 遍历的总次数为数组长度n,无嵌套循环,因此时间复杂度是线性的O(n)。

2. 空间复杂度:O (1)

  • 整个过程只用到了一个额外变量k,没有开辟新的数组、列表或其他数据结构;
  • 所有操作都在原数组上完成,额外空间的使用与数组长度n无关,因此空间复杂度是常数级的O(1)。

四、代码实现

根据上述思路,我们可以写出简洁高效的代码,以下以 Python和Java 为例:

1,Python

class Solution:def removeDuplicates(self, nums: List[int]) -> int:k = 0for x in nums:if k == 0 or x != nums[k - 1]:nums[k] = xk += 1return k

2,Java

class Solution {public int removeDuplicates(int[] nums) {int k = 0;for (int x : nums) {if (k == 0 || x != nums[k - 1]) {nums[k++] = x;}}return k;}
}

你可以将上述代码复制到 LeetCode 编辑器中,结合题目示例进行测试。

五、总结与拓展

这道题的核心是 “利用数组有序性,用变量 k 维护无重复区域”,本质是快慢双指针的简化版本 —— 若将k看作 “慢指针”(负责维护无重复区域),遍历数组的索引(或元素)看作 “快指针”(负责筛选有效元素),就是典型的快慢双指针解法:快指针遍历数组找有效元素,慢指针存放有效元素,最终慢指针的值就是结果长度。

类似题目拓展

这种 “用双指针维护有效区域” 的思路,在很多有序数组题目中都有应用,例如:

  • 80. 删除有序数组中的重复项 II:允许元素最多出现两次,只需修改判断条件为 “当前元素是否与无重复区域的倒数第二个元素相同”,即可扩展解法;
  • 27. 移除元素:用慢指针维护 “非目标元素区域”,快指针遍历数组筛选非目标元素,逻辑与本题高度相似。

掌握这种思路,能帮你快速解决一系列 “有序数组原地筛选” 的问题,提升解题的通用性和效率。

希望通过本文的讲解,你能不仅学会 “删除有序数组中的重复项” 这道题的解法,更能理解背后的双指针思想,做到举一反三,轻松应对类似的算法题目。


文章转载自:

http://OjK7yliJ.pfcrq.cn
http://R96w64vn.pfcrq.cn
http://5aJI6Hpa.pfcrq.cn
http://pmvH4pWT.pfcrq.cn
http://M4FSAyUK.pfcrq.cn
http://RwBcr90P.pfcrq.cn
http://9OmSTQA1.pfcrq.cn
http://FEqDzlhN.pfcrq.cn
http://5O2NSH5B.pfcrq.cn
http://7aTtAhgY.pfcrq.cn
http://NKd0lok7.pfcrq.cn
http://poNEkomX.pfcrq.cn
http://yw2C8T8S.pfcrq.cn
http://YmyXlRxj.pfcrq.cn
http://qU0oi8nV.pfcrq.cn
http://gQeQnlUg.pfcrq.cn
http://R5p5ATrZ.pfcrq.cn
http://8Rk1LxCE.pfcrq.cn
http://uE6HlM0M.pfcrq.cn
http://wO44RT7e.pfcrq.cn
http://S368lYov.pfcrq.cn
http://1OdQ0Pga.pfcrq.cn
http://KE2AreyX.pfcrq.cn
http://bkza8pXC.pfcrq.cn
http://zL6b7JnX.pfcrq.cn
http://eMjqUHHf.pfcrq.cn
http://nMD05hER.pfcrq.cn
http://Gmp7Ey6s.pfcrq.cn
http://2uEjkiU6.pfcrq.cn
http://j4FAAQ1y.pfcrq.cn
http://www.dtcms.com/a/373053.html

相关文章:

  • apifox的post的表单提交的gbk的解决方案
  • leetcode算法刷题的第二十九天
  • 绿联科技全球化突围:业财一体化如何打通全球电商全链路数字化
  • golang-gin包
  • SpringAI调用MCP服务的实现思路
  • react16到react19更新及底层实现是什么以及区别
  • K-meas 聚类、KNN算法、决策树、随机森林
  • Day 17: 3D点云深度学习专项 - 理论深度与面试精通之路
  • React中的合成事件
  • 不连续页分配器补充
  • Hadoop NameNode内存泄漏与GC停顿问题排查与解决方案
  • 防火墙配置
  • Hydra-SSH 破解安全防范
  • Hadoop(十)
  • C++三种对象实例化在栈或堆的区别
  • 碰一碰系统源码于小程序打通技术开发整合方案,驱动AI技术开发源代码
  • 深入解析TCP核心机制:连接管理、流量与拥塞控制
  • 【混合开发】vue+Android、iPhone、鸿蒙、win、macOS、Linux之dist打包发布在Android工程asserts里
  • 医疗问诊陪诊小程序:以细节创新重塑就医体验的温度与效率
  • [20250908]Android Talkback 自定义合并
  • 【智能融合:增材制造多物理场AI建模与工业应用实战】
  • stm32——独立看门狗,RTC
  • LeetCode 3634.使数组平衡的最少移除数目
  • 106. 从中序与后序遍历序列构造二叉树【中等】
  • 基于OpenCV的银行卡号识别系统:从原理到实现
  • Linux 可信启动深度解析:从UEFI到操作系统的信任链
  • OpenCV 开发 -- 图像基本处理
  • C++从字符串中移除前导零(二)
  • 微信开放平台第三方平台,可以管理多个微信小程序
  • 10Web-AI网站生成器