力扣(删除有序数组中的重复项I/II)

发布于:2025-08-10 ⋅ 阅读:(26) ⋅ 点赞:(0)

在 LeetCode 的数组类题目中,有序数组去重是经典且高频的题型 。今天我们聚焦 删除有序数组中的重复项(题号 26) 和 删除有序数组中的重复项 II(题号 80) ,用双指针技巧优雅解决,带你理清解题思路,掌握这类题的通用解法。

一、题目回顾与分析

(一)删除有序数组中的重复项(简单)

题目要求:给一个非严格递增的数组nums,原地删除重复元素,让每个元素仅出现一次,保持相对顺序,返回新长度k,且需保证numsk个元素是唯一元素并按初始顺序排列。

(二)删除有序数组中的重复项 II(中等)

题目要求:同样原地操作,不过允许元素最多出现两次,超过两次的重复元素需删除,返回处理后数组新长度。

这两道题核心都是 “原地修改” ,要控制额外空间复杂度为O(1),双指针是绝佳选择 —— 用指针标记有效元素位置,遍历数组处理重复情况。

二、双指针解法逻辑拆解

(一)题目 26:每个元素仅出现一次

class Solution {
    public int removeDuplicates(int[] nums) {
        // 特殊情况处理:数组为空直接返回0
        if (nums.length == 0) return 0; 
        // 双指针,key指向“待填充唯一元素”的位置,初始在第一个元素
        int key = 0; 
        // len遍历数组,从第二个元素开始对比
        for (int len = 1; len < nums.length; len++) { 
            // 发现当前元素与key位置元素不同,说明是新的唯一元素
            if (nums[key] != nums[len]) { 
                key++; // key移动到下一个待填充位置
                nums[key] = nums[len]; // 将不同元素放到key位置
            }
        }
        // key从0开始,所以有效长度是key + 1
        return key + 1; 
    }
}

逻辑详解:

  • 指针分工key是 “慢指针”,标记当前已处理好的唯一元素的最后位置;len是 “快指针”,负责遍历数组找新元素。
  • 核心判断:当nums[len] != nums[key],说明遇到新的唯一元素,把len位置元素挪到key + 1位置(key先自增再赋值 ),保证numskey + 1个元素是去重后的结果。比如数组[1,1,2],初始key=0len=1时元素相同不处理;len=2nums[2]=2 != nums[0]=1key变为 1,nums[1]=2,最终数组前2个元素[1,2],返回2

(二)题目 80:元素最多出现两次

class Solution {
    public int removeDuplicates(int[] nums) {
        // 数组长度小于3时,本身就满足“最多出现两次”,直接返回原长度
        if (nums.length <= 2) return nums.length; 
        // key初始指向第三个位置(索引2),因为前两个元素不管是否重复都可保留
        int key = 2; 
        // len从第三个元素开始遍历(索引2)
        for (int len = 2; len < nums.length; len++) { 
            // 对比当前元素与“往前数第二个有效位置”的元素
            if (nums[key - 2] != nums[len]) { 
                // 不同则说明可作为新的有效元素,放到key位置
                nums[key] = nums[len]; 
                key++; // key后移,标记下一个待填充位置
            }
        }
        return key; 
    }
}

逻辑详解:

  • 指针逻辑升级:因为允许最多两次重复,所以判断条件变为 nums[key - 2] != nums[len] 。key - 2 位置能反映 “前面已经保留的元素情况”—— 若当前遍历元素和 key - 2 位置元素不同,说明加入后不会超过两次重复(比如数组[1,1,1,2,2,3]key初始为 2,len=2nums[0] == nums[2],不处理;len=3nums[1] != nums[3]nums[1]=1nums[3]=2 ),把2放到key=2位置,key变为 3 ,以此类推,最终前key个元素满足最多两次重复的要求。
  • 边界处理:数组长度小于等于 2 时,本身无需处理,直接返回原长度,简化逻辑。

三、两道题的共性与差异总结

(一)共性

  1. 双指针模式:都用两个指针,一个(key)标记有效元素的边界,一个(len)遍历数组找新元素,通过对比决定是否 “接纳” 当前元素到有效区域。
  2. 原地修改:不依赖额外数组存储结果,直接在原数组上覆盖、调整,契合题目空间复杂度要求。

(二)差异

  • 重复次数限制:题目 26 限制 “最多 1 次”,所以对比条件是和key位置元素是否相同;题目 80 允许 “最多 2 次”,对比条件变为和key - 2位置元素是否相同,通过调整对比的 “参考位置”,灵活控制重复次数。
  • 指针初始值与返回值:题目 26 需考虑数组为空情况,key从 0 开始,返回key + 1;题目 80 数组长度小于 3 时直接返回原长度,key初始从 2 开始,返回key即可,反映出不同重复次数限制下,有效区域的初始化和结果计算的细微区别。

网站公告

今日签到

点亮在社区的每一天
去签到