LeetCode26 删除有序数组中的重复项(带扩展)

48 阅读2分钟

leetcode.cn/problems/re…

image.png image.png

解法一:双指针

由于数组已经排好序,我们让慢指针 slow 走在后面,快指针 fast 走在前面探路,找到一个不重复的元素就告诉 slow 并让 slow 前进一步,将该元素赋值给 nums[slow]。这样当 fast 指针遍历完整个数组 nums 后,nums[0..slow] 就是不重复元素,元素个数即为该子数组长度 slow+1。

func removeDuplicates(nums []int) int {
    if len(nums) == 0{
        return 0
    }
    slow, fast := 0, 0
    for fast < len(nums){
        if nums[fast] != nums[slow]{ // 维护 nums[0..slow] 无重复
            slow++
            nums[slow] = nums[fast]
        }
        fast++
    }
    // 数组长度为索引 + 1
    return slow+1
}

扩展:删除有序数组中的重复项 II

image.png image.png

解法一:双指针法

在之前的解法中添加一个 count 变量记录每个数字重复出现的次数

func removeDuplicates(nums []int) int {
    if len(nums) <= 2{ // 前2个数默认保留
        return len(nums)
    }
    // 快慢指针,维护 nums[0..slow] 为结果子数组
    slow, fast := 0, 0
    // 记录一个元素重复的次数
    count := 0
    for fast < len(nums) {
        if nums[fast] != nums[slow] {
            // 此时,对于 nums[0..slow] 来说,nums[fast] 是一个新的元素,加进来
            slow++
            nums[slow] = nums[fast]
        } else if slow < fast && count < 2 {
            // 此时,对于 nums[0..slow] 来说,nums[fast] 重复次数小于 2,也加进来
            slow++
            nums[slow] = nums[fast]
        }
        fast++
        count++
        // 当快指针遇到新元素时,重置计数器
        if fast < len(nums) && nums[fast] != nums[fast-1] {
            count = 0
        }
    }
    // 数组长度为索引 + 1
    return slow + 1
}

解法二:压栈思路

用一个栈记录去重后的元素,如果当前元素等于栈顶下方那个数(倒数第二个数),那么不能入栈(否则会有三个一样的数),反之可以入栈。

eg: nums = [1,1,1,2,2,3]

由于数组是有序的,前两个数一定满足要求(因为即使重复也至少保留2个),直接入栈。 从第3个数字(i = 2起)开始考虑 image.png 最终栈中元素为 [1,1,2,2,3]。

为了做到 O(1) 空间复杂度,直接把 nums 当作栈,用一个变量 stackSize 表示栈的大小,初始值为 2。

那么 nums[stackSize−1]为栈顶元素,nums[stackSize−2] 就是栈顶下方那个数。

入栈就是把 nums[stackSize] 置为 nums[i],同时把 stackSize 加一。

func removeDuplicates(nums []int) int {
    if len(nums) <= 2{ // 2个元素内不需要删除任何元素
        return len(nums)
    }
    // 数组是排好序的,所以重复的元素都是连续的
    stackSize := 2 // 前2个元素不管重复与否,默认保留
    // 从第三个元素开始判断
    for i:=2; i < len(nums); i++{
        if nums[i] != nums[stackSize-2] { // 和栈顶下方的元素比较
            nums[stackSize] = nums[i] // 可以入栈
            stackSize++
        } 
    }
    return stackSize
}