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

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

2,Java

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. 移除元素:用慢指针维护 "非目标元素区域",快指针遍历数组筛选非目标元素,逻辑与本题高度相似。

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

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

相关推荐
不枯石1 小时前
Matlab通过GUI实现点云的均值滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab·均值算法
不枯石1 小时前
Matlab通过GUI实现点云的双边(Bilateral)滤波(附最简版)
开发语言·图像处理·算法·计算机视觉·matlab
白水先森3 小时前
C语言作用域与数组详解
java·数据结构·算法
想唱rap3 小时前
直接选择排序、堆排序、冒泡排序
c语言·数据结构·笔记·算法·新浪微博
老葱头蒸鸡4 小时前
(27)APS.NET Core8.0 堆栈原理通俗理解
算法
视睿4 小时前
【C++练习】06.输出100以内的所有素数
开发语言·c++·算法·机器人·无人机
柠檬07115 小时前
matlab cell 数据转换及记录
算法
YuTaoShao6 小时前
【LeetCode 每日一题】2221. 数组的三角和
数据结构·算法·leetcode
little~钰6 小时前
树上倍增和LCA算法---上
算法
力扣蓝精灵6 小时前
今日分享 整数二分
算法