80. 删除有序数组中的重复项 II

80. 删除有序数组中的重复项 II

✨核心逻辑

本题采用 双指针(快慢指针) 的策略:

  1. 有序数组特性:由于数组是严格递增的,因此重复的元素必然是连续相邻的。
  2. 容错上限:题目允许每个元素最多出现两次。这意味着,对于一个“新”元素,只要它与它前面相隔两个位置的元素不相同,它就完全没有超过限制,可以放心保留。
  3. 双指针分工
    • 慢指针 slow 负责存放符合条件的有效新数组的元素,指向下一个可以放置新元素的位置。
    • 快指针 i 负责遍历原数组,寻找符合条件的元素。
  4. 原地修改:直接在 nums 数组上覆盖写入,不需要额外的数组空间。

🔥代码实现(含详细变量注释)

class Solution {
    public int removeDuplicates(int[] nums) {
        // 如果数组长度小于等于 2,那么数组本身天然满足“最多重复两次”的条件,直接返回当前长度
        if (nums.length <= 2) {
            return nums.length;
        }
        
        // slow:慢指针,指向“结果数组”中下一个待填充的位置。
        // 因为前两个元素(索引0和1)必定可以保留,所以从索引2开始作为待写入点
        int slow = 2;
        
        // i:快指针,用于遍历原数组,检查每一个位置的元素是否符合要求
        for (int i = 2; i < nums.length; i++) {
            // 核心判断:如果当前快指针指向的元素 nums[i],
            // 不等于它前面相隔两个位置的元素 nums[slow - 2],
            // 说明当前元素还没达到“重复3次及以上”的情况,是一个合法的新元素。
            if (nums[slow - 2] != nums[i]) {
                // 将这个合法的元素,覆盖写入到慢指针指向的位置
                nums[slow] = nums[i];
                // 写入后,慢指针向前移动一步,准备接收下一个有效元素
                slow++;
            }
        }
        
        // 循环结束时,慢指针 slow 的值正好等于新数组的长度
        return slow;
    }
}
  • ⏱️复杂度分析
    • 时间复杂度:O(N),其中 N 是数组的长度。快指针 i 从头到尾只需要遍历一次数组,每次循环仅进行常数次的比较和赋值操作。

    • 空间复杂度:O(N),其中 N 是数组的长度。快指针 i 从头到尾只需要遍历一次数组,每次循环仅进行常数次的比较和赋值操作。