LeetCode: 80. 删除有序数组中的重复项 II(swift)

95 阅读1分钟

中等

给你一个有序数组 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 * 104
  • 104 <= nums[i] <= 104
  • nums 已按升序排列

    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
}