阅读目录
- 1. 题目
- 2. 解题思路
- 3. 代码实现
1. 题目
2. 解题思路
- 让
index
指向删除重复元素后数组的新长度; - 让
st_idx
指向重复元素的起始位置,而i
指向重复元素的结束位置,duplicate_num
代表重复元素的个数; - 一段重复元素结束后,这时候如果
st_idx = index
,那么无需搬移数据,只让index
前进最多 2 个位置即可,如上面上图到右图的过程所示; - 如果
st_idx != index
,我们需要从st_idx
开始最多搬移 2 个数据到index
位置,如上面右图到左图的过程所示; - 此时,如果
i
指向最后一个元素,那么直接将最后一个元素搬移到index
位置,直接返回; - 如果
i
还没有到最后一个元素,那么继续重复寻找下一段重复元素;
3. 代码实现
class Solution:def removeDuplicates(self, nums: List[int]) -> int:if len(nums) < 3:return len(nums)index = 0st_idx = 0duplicate_num = 1i = 1target = nums[0]while i < len(nums):while i < len(nums) and nums[i] == target:duplicate_num += 1i += 1if st_idx != index:for j in range(st_idx, st_idx+min(duplicate_num, 2)):nums[index] = nums[st_idx]st_idx += 1index += 1else:index += min(2, duplicate_num)if i == len(nums) - 1:nums[index] = nums[i]index += 1return indexif i < len(nums):st_idx = itarget = nums[i]duplicate_num = 1i += 1return index
时间复杂度为 O ( n ) O(n) O(n),最多遍历 2 遍数组,空间复杂度为 O ( 1 ) O(1) O(1)。
当然了,上面的思路不容易理清,比较简单的一个实现是利用快慢指针。一开始快慢指针都指向第 3 个元素,如果 nums[fast] = nums[slow-2]
,说明重复元素超过了 2 个,只需要向前移动 fast
指针即可;如果 nums[fast] != nums[slow-2]
,那么把 fast
指针指向的元素移动到slow
指针,二者都前进一步。最后,slow指针指向的位置即为结果所求。
class Solution {
public:int removeDuplicates(vector<int>& nums) {if (nums.size() < 3)return nums.size();int slow = 2;int fast = 2;while (fast < nums.size()) {if (nums[fast] == nums[slow-2]) {fast++;} else {nums[slow++] = nums[fast++];}}return slow;}
};