本次刷题日记的第 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
今天就到这里,学习所得,若有偏差,还请斧正
欢迎点赞,关注,收藏
朋友们,你的支持和鼓励,是我坚持分享,提高质量的动力
好了,本次就到这里
技术是开放的,我们的心态,更应是开放的。拥抱变化,向阳而生,努力向前行。
我是阿兵云原生,欢迎点赞关注收藏,下次见~