中等
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
说明:
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以**「引用」**方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
//nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
示例 1:
输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length =5, 并且原数组的前五个元素被修改为1, 1, 2, 2,3。 不需要考虑数组中超出新长度后面的元素。
示例 2:
输入:nums = [0,0,1,1,1,1,2,3,3]
输出:7, nums = [0,0,1,1,2,3,3]
解释:函数应返回新长度 length =7, 并且原数组的前五个元素被修改为0,0,1,1,2,3,3 。 不需要考虑数组中超出新长度后面的元素。
提示:
1 <= nums.length <= 3 * 104104 <= nums[i] <= 104nums已按升序排列
func removeDuplicates(_ nums: inout [Int]) -> Int {
// 数组长度小于等于2时,不需要删除重复项,直接返回数组长度
if nums.count <= 2 {
return nums.count
}
// 定义变量 i 表示有效元素的下标,初始值为 1
var i = 1
// 定义变量 count 表示当前数字出现的次数,初始值为 1
var count = 1
// 遍历数组,从第二个元素开始,因为第一个元素必然是有效元素
for j in 1..<nums.count {
// 如果当前元素和前一个元素相同
if nums[j] == nums[j - 1] {
// 如果当前数字出现的次数小于等于2,将其标记为有效元素,并将有效元素的下标 i 加 1
if count < 2 {
nums[i] = nums[j]
i += 1
}
// 将当前数字出现的次数加 1
count += 1
} else {
// 如果当前元素和前一个元素不同,将其标记为有效元素,并将有效元素的下标 i 加 1
nums[i] = nums[j]
i += 1
// 将当前数字出现的次数重置为 1
count = 1
}
}
// 返回有效元素的个数
return i
}
上述代码的解题思路如下:
题目要求删除有序数组中的重复项,但是每个数字最多出现两次。因此,我们可以定义一个变量 count 来记录当前数字出现的次数,如果当前数字出现的次数小于等于2,则将其标记为有效元素。如果当前数字出现的次数大于2,则将其标记为无效元素,继续遍历数组。最终,将有效元素放在数组的前面,并返回有效元素的个数。
优化一下代码:
func removeDuplicates(_ nums: inout [Int]) -> Int {
let length = nums.count
if length < 3 { return length }
var slow = 2, fast = 2 // 定义 0..<slow 为满足题意的区间
while fast < length {
// 重点是理解这里的 slow 的含义
// slow 代表一个坑位,我们要确保 nums[slow-2] != nums[slow]
// 那我们就需要找到每一个与 nums[slow-2] 不同的值填入 nums[slow]
if nums[fast] != nums[slow - 2] {
nums[slow] = nums[fast]
slow += 1
}
fast += 1
}
return slow
}