#LC80. 删除有序数组中的重复项 II
删除有序数组中的重复项 II
LeetCode80这道题在LeetCode上是一道经典的数组处理题目,考察的是 双指针(Two Pointers) 技巧以及 原地算法(In-place Algorithm) 的设计能力。在NOI/NOIP竞赛中,这类题目通常作为考察思维严谨性和代码实现基础的签到题出现,或者作为复杂数据结构题的一部分。
为了适应竞赛训练,我将原题改编成了标准的OI题目格式(Standard I/O),并着重强调了空间复杂度的限制。
题目:删除有序数组中的重复项 II (Remove Duplicates from Sorted Array II)
题目描述
给定一个已排序的整数数组 nums,请你原地删除重复出现的元素,使得出现次数超过两次的元素只出现两次。返回删除后数组的新长度。
你需要满足以下严格限制:
- 原地修改:不要使用额外的数组空间,你必须在 的额外空间条件下完成。
- 相对顺序:元素的相对顺序应该保持一致。
- 结果验证:你的程序需要输出处理后的新长度
len,以及数组前len个元素。
注意:这道题的核心不在于输出,而在于如何高效地在原数组上进行数据搬运和覆盖。
输入格式
第一行包含一个整数 ,表示数组 nums 的长度。
第二行包含 个整数,表示数组 nums 的元素。保证输入的数组是非递减有序的。
输出格式
第一行输出一个整数,表示处理后的新长度 len。
第二行输出 len 个整数,表示处理后的数组前 len 个元素,整数之间用空格分隔。
样例输入 1
6
1 1 1 2 2 3
样例输出 1
5
1 1 2 2 3
样例说明:函数应该返回新的长度 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3。不需要考虑数组中超出新长度后面的元素。
样例输入 2
9
0 0 1 1 1 1 2 3 3
样例输出 2
7
0 0 1 1 2 3 3
样例说明:函数应该返回新的长度 7, 并且原数组的前七个元素被修改为 0, 0, 1, 1, 2, 3, 3。
数据范围与提示
- 数组严格按非递减顺序排列。
- 空间复杂度限制:必须为 ,即除了几个变量外,不得开辟与 相关的辅助数组(如
vector<int> temp(N)是不允许的)。
教练的解题思路提示 (Pseudo-code)
这道题的关键在于维护两个指针:
- 遍历指针 (
fast):用于读取数组中的每一个元素。 - 放置指针 (
slow):指向当前有效结果数组的末尾(即下一个待填入数据的位置)。
因为题目允许元素最多出现两次,所以判断是否保留当前元素的依据是:它是否和结果数组中倒数第二个元素相同。
NOI C++14 风格伪代码提示:
/*
核心函数逻辑提示
假设数组为 A,长度为 n
*/
Function solve(A, n):
// 1. 处理边界情况
IF n <= 2 THEN
RETURN n // 长度小于等于2,无需删除,直接返回
END IF
// 2. 初始化双指针
// slow 指针定义:当前“合法区域”的下一个写入位置
// 因为前两个元素一定合法(无论是否重复),所以 slow 从 2 开始
INTEGER slow = 2
// 3. fast 指针从第3个元素(下标2)开始遍历整个数组
FOR fast FROM 2 TO n - 1 DO
// 【核心逻辑】
// 检查 A[fast] 是否可以放入合法区域
// 条件:A[fast] 不等于 A[slow - 2]
// 原因:如果 A[fast] == A[slow - 2],且数组是有序的,
// 说明 A[slow-2], A[slow-1], A[fast] 三者相同(或者更多),
// 此时 A[fast] 是第三个重复项,需要丢弃。
// 反之,如果不等,说明 A[fast] 最多是该数值的第1个或第2个,可以保留。
IF A[fast] != A[slow - 2] THEN
A[slow] = A[fast] // 将 fast 指向的值搬运到 slow 位置
slow = slow + 1 // 合法区域长度 + 1
END IF
END FOR
// 4. 返回新长度
RETURN slow
知识点总结 (Knowledge Points)
在做这道题时,你需要掌握以下核心考点:
- 双指针法 (Two Pointers):利用快慢指针在一个数组中同时进行读写操作,快指针负责寻找新元素,慢指针维护有效数据的边界。
- 有序数组特性 (Sorted Array Property):因为数组有序,重复元素必然相邻。这简化了判重逻辑,不需要哈希表。
- 原地操作 (In-place Operations):直接在输入数组上修改,通过覆盖旧数据来达到删除效果,理解覆盖与交换的区别。
- 边界条件处理:考虑数组长度小于等于 2 的情况,这是不需要处理的基准情况 (Base Case)。