深入解析:删除有序数组中的重复项 II——巧用双指针实现条件筛选
深入解析:删除有序数组中的重复项 II——巧用双指针实现条件筛选
在算法世界里,数组去重 是一道经典问题,尤其是面对 有序数组 时,我们如何在 保证元素相对顺序 的前提下,高效去重?LeetCode 第 80 题 “删除有序数组中的重复项 II” 就是这样一道挑战题。今天,我将深入解析 双指针技巧 如何帮我们解决这个问题,并通过 详细代码讲解,让你彻底掌握它的核心思想。
1. 题目理解
题目要求:
- 在一个升序排列的数组中,删除重复的元素,但最多保留两个相同的元素。
- 返回新数组的长度,并保证原数组的前部分存储的是处理后的元素。
- 要求使用 O(1) 额外空间(即不能借助额外的数组存储)。
示例
输入: nums = [1,1,1,2,2,3]
输出: 5
处理后的数组: [1,1,2,2,3]
可以看到:
- 原本 “1” 出现了三次,但我们只能 保留两个,因此去掉一个 “1”;
- “2” 也出现了两次,符合要求,保留;
- “3” 只出现了一次,符合要求,保留。
2. 解决思路——双指针法
由于数组 有序,我们可以利用 双指针技巧:
- 快指针 (
i
) 负责遍历整个数组,寻找符合条件的元素; - 慢指针 (
j
) 负责 存储符合条件的元素,保证最终数组的正确性。
同时,我们需要一个 计数变量 count
,用于记录当前数字出现的次数:
- 如果当前元素次数 ≤ 2,则将其存入结果数组;
- 否则,跳过该元素。
3. 代码详解
def removeDuplicates(nums):# 边界条件:空数组直接返回0if not nums:return 0# 初始化双指针:j 指向存储位置,count 记录当前元素出现次数j = 0 # 慢指针,最终数组的索引count = 1 # 当前元素出现次数# 遍历整个数组(快指针 i)for i in range(1, len(nums)):if nums[i] == nums[i - 1]: # 如果当前元素与前一个相同count += 1else:count = 1 # 新数字,重置计数if count <= 2: # 只存储最多两个相同元素j += 1nums[j] = nums[i] # 赋值到正确位置return j + 1 # 返回新数组长度
4. 代码解析
(1) 双指针逻辑
i
从索引 1 开始遍历,用于检查每个元素;j
存储符合条件的元素,保证最终数组正确。
(2) 条件筛选
- 通过
count
记录 当前元素出现次数:- 若 小于等于 2,则 存入数组;
- 若 超过 2,则 跳过,保证去重。
5. 示例运行
让我们来看实际执行过程:
nums = [1,1,1,2,2,3]
length = removeDuplicates(nums)
print(nums[:length]) # 输出:[1,1,2,2,3]
执行步骤:
- 处理
1,1,1
-> 保留1,1
,去掉多余1
; - 处理
2,2
-> 保留2,2
; - 处理
3
-> 保留3
。
最终得到 去重后的数组 [1,1,2,2,3]
。
6. 时间复杂度与优化
- 时间复杂度:O(n),因为我们只遍历一次数组;
- 空间复杂度:O(1),不需要额外存储,仅靠原数组操作。
对于大数据场景,这是一个 高效且实用 的算法!
7. 结语:双指针——数组处理的神兵利器
这道题 充分考验了数据筛选与指针操作:
- 通过 快慢指针 实现数组的 原地去重;
- 通过 计数变量 确保符合 最多保留 2 个元素 的规则;
- 代码结构清晰、逻辑合理,在实际开发中也能派上用场。