【刷题日记】 80. 删除有序数组中的重复项 II

1,296 阅读4分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第17天,点击查看活动详情

本次刷题日记的第 37 篇,力扣题为:80. 删除有序数组中的重复项 II中等

一、题目描述:

看到这道题,咱们是什么感受,至少对于空间复杂度的指标是限制死了, O(1),雷打不动的

二、这道题考察了什么思想?你的思路是什么?

仔细来分析一下这道题,从一个有序数组中删除重复的项,瞅瞅有啥重点信息:

  • 题目给出的有序数组,是一个从小到大排列的数组,数组中的元素是整数,每个整数重复的次数不一样
  • 我们需要直接修改传入的数组中的数据,去掉数组重复超过 2 次的数字,把他当成是一个引用传递的数据,咱们的修改,调用者自身是知道的

见到过了一下重要信息之后,我们的脑海里是否会浮现出一个条件反射出来的想法?

直接遍历这个数组,用当前的数组去和左边的数字进行比较,若出现了 1 次相等,那么可以继续往下走,若出现了 2 次相等,则认为现在已经是同一个数字有 3 次重复了

这个时候,就需要将当前位置之后的数据,全部往前覆盖 1 位,然后从刚才的位置,继续向后遍历,做法和前面一样,直到遍历完毕

当然这种方式也是可以做出来,就是咱们对于数据覆盖的操作有点多,不太可取,例如效果是这样的

这样子会产生大量无用的覆盖操作,耗时耗力,显然,肯定有一个更好的方式

咱们可以使用双指针的方式来实现,虽然也会出现覆盖,但是覆盖的都是必须要覆盖的操作,而不一些无用的覆盖操作,我们可以这样来做

绿色代表慢指针,红色代表快指针,每一次比较,都是快指针上的数字和慢指针-2 上的数字做对比,因为题目要求是可以同一个数字重复 2 次的

可以看到对比上述例子,双指针的方式,这里只精准覆盖了 3 个数字,对于上述例子,是覆盖了 7 个数字,当数据量大的时候,对比就会更加明显

根据上述思路,我们来进行编码就是一件很容易的事情了

三、编码

根据上述逻辑和分析,我们就可以翻译成如下代码,编码实现的时候,需要注意一点的是

我们的slow 指针和 fast 指针没有必要从 0 开始了,根据题目给出的要求,相同的数字是可以重复 2 次的,

则咱们可以直接从 第 3 个数字开始校验,跳过数组的前面 2 个数字,

跳过的这 2 个数字,可能是重复的,也可能是不重复的,但是对于我们的实现是没有影响的

func removeDuplicates(nums []int) int {
    // 定义1个快指针,1个慢指针
    fast,slow := 2,2

    // 遍历整个数组
    length := len(nums) 
    // 快指针一定是跑在慢指针的前面,所以用快指针来控制循环的次数
    for fast < length {
        if nums[slow-2] != nums[fast]{
            // 说明此时没有连续3个以上的相同数字
            nums[slow] = nums[fast]
            slow++
        }
		// 说明这里有同一个数字重复 3 次以上的情况了
        fast++
    }
    // 此处是返回符合条件的长度,slow 正好是符合条件的长度
    return slow
}

使用双指针的方式来实现题目,还是比较常见的,很多情况下是可以大大的降低时间复杂度和空间复杂度的,且使用起来也比较方便,可以慢慢的感受一下双指针的魅力

四、总结:

很明显了,我们这种实现的方式,时间复杂度是 O(n) ,具体的 n 控制的循环次数是快指针跑动的次数

那么这里的空间复杂度就更明确了,我们并未引入太多的空间消耗,只是一些常数级别的空间消耗,则这里的空间复杂度是 O(1)

原题地址:80. 删除有序数组中的重复项 II

今天就到这里,学习所得,若有偏差,还请斧正

欢迎点赞,关注,收藏

朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力

好了,本次就到这里

技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。

我是小魔童哪吒,欢迎点赞关注收藏,下次见~