80. 删除有序数组中的重复项 II
✨核心逻辑
本题采用 双指针(快慢指针) 的策略:
- 有序数组特性:由于数组是严格递增的,因此重复的元素必然是连续相邻的。
- 容错上限:题目允许每个元素最多出现两次。这意味着,对于一个“新”元素,只要它与它前面相隔两个位置的元素不相同,它就完全没有超过限制,可以放心保留。
- 双指针分工:
- 慢指针
slow负责存放符合条件的有效新数组的元素,指向下一个可以放置新元素的位置。 - 快指针
i负责遍历原数组,寻找符合条件的元素。
- 慢指针
- 原地修改:直接在
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 从头到尾只需要遍历一次数组,每次循环仅进行常数次的比较和赋值操作。