算法训练营第十一天| 删除有序数组中的重复项 II
一、今日学习任务今日任务80. 删除有序数组中的重复项 II 巩固滑动窗口算法提交第二周学习小结题意给你一个有序数组 nums 请你 原地 删除重复出现的元素使得出现次数超过两次的元素只出现两次 返回删除后数组的新长度。不要使用额外的数组空间你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。题目链接https://leetcode.cn/problems/remove-duplicates-from-sorted-array-ii/视频链接https://www.bilibili.com/video/BV18G5UzzE8c/二、自己看到题目的第一想法看到“删除重复项”和“有序数组”第一反应还是用双指针。但这次条件变了——每个元素最多出现两次不是一次。相当于 Day10 删除有序数组中的重复项题目的“升级版”。删除有序数组中的重复项的逻辑是“只要当前元素和前一个不同就保留”那这次是不是改成“只要当前元素和前面第二个元素不同就保留”因为前面已经保留了最多两个相同元素如果当前元素和“前面第二个”元素相同说明它至少是第三个重复的了应该跳过。三、实现过程中遇到哪些困难慢指针的初始值怎么确定Day10 里 slow 从 1 开始因为第一个元素肯定保留。这道题前两个元素最多重复两次所以 slow 应该从 2 开始才对。如果数组长度小于等于 2直接返回原长度就行。比较逻辑想不通一开始想用 count 变量记录当前元素出现了几次超过 2 就跳过否则保留。代码写出来很臃肿要额外维护 count。后来看到题解里“和 slow-2 比较”的写法才发现更简洁因为我们只关心当前元素会不会成为“第三个重复元素”而前面已经保留了最多两个重复元素所以只需要判断当前元素是否等于 slow 指针往前两个位置的元素就行。对 Day10 的思维惯性习惯性用 Day10 的模板nums[fast] ! nums[slow-1]但这里要用nums[fast] ! nums[slow-2]。一开始写错成slow-1导致结果不对调试了一下才发现问题。四、代码是怎么实现的思路快慢指针都从下标 2 开始。前两个元素一定保留。快指针遍历数组比较nums[fast]和nums[slow-2]即已经保留的倒数第二个元素。如果不相等说明当前元素不会造成“第三个重复”就把它放到 slow 位置slow 后移如果相等说明当前元素已经是第三个重复跳过。最后返回 slow 即为新数组长度。class Solution { public: int removeDuplicates(vectorint nums) { int n nums.size(); if (n 2) return n; int slow 2; for (int fast 2; fast n; fast) { if (nums[fast] ! nums[slow - 2]) { nums[slow] nums[fast]; slow; } } return slow; } };五、今日收获心得1、这道题是 Day10 的延伸核心思路还是双指针。Day10 是比较 nums[fast] 和 nums[slow-1]这道题是比较 nums[fast] 和 nums[slow-2]。掌握了模板后改一个数字就能适应不同的“最多重复次数”要求。2、如果题目改成“每个元素最多出现 k 次”那比较对象就是 nums[slow-k]。这个规律很重要能举一反三。3、带计数变量的解法虽然代码长一点但逻辑更直观遇到重复就 count不重复就重置 count。两种解法都值得掌握。4、前几个元素的处理方式很关键Day10 前 1 个元素保留这道题前 2 个元素保留。所以慢指针初始值就是“需要保留的元素个数”。