力扣 80. 删除有序数组中的重复项 II 同向快慢双指针

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

示例 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 已按升序排列

题解

在原表基础上修改,用两个同向指针,一慢一快 slow=0 fast=1,向右遍历原表,cnt=0记录重复次数,

同时slow是新表(在原表上修改得到)的长度下标,slow到哪里则新表更新到了哪里;

  • 对比slowfast位置的元素,如果相等,即nums[slow]==nums[fast],说明是同一个元素(题目允许最多保留两个相同元素),记为A,用cnt++记录出现次数,接下来判断处理:
    • 如果cnt==1,A刚好出现了两次,题目需要保留A两次,先将slow++,新表的长度加一,接下来给此位置赋值, nums[slow]=nums[fast];;注意A记录了两次,因为slow++前可以省略num[slow]=A,因为num[slow]本来就=A,不需要写这一句
    • 如果cnt!=1,则A出现了不止两次,因为之前出现两次我们已经保留过了,此时我们不需要再保留A,那我们就不用处理了
    • fast++,不管A出现几次,fast都要右移
  • nums[slow]!=nums[fast],将两个元素记为A,B,因为A是已经处理过的元素,而B是新出现的,所以我们将B添加到新表中,先将slow增加一,再把B赋值给这个位置,最后将fast右移,写成一句:nums[++slow]=nums[fast++];再重置cnt

查看代码
class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int slow=0,fast=1;
        int cnt=0;
        while(fast<nums.size()){
            if(nums[slow]==nums[fast]){
                cnt++;
                if(cnt==1){//slow 和 fast 指向一样,说明此元素出现两次
                    slow++;
                    nums[slow]=nums[fast];//
                }
                //大于两次不予处理
                //移动
                fast++;
            }
            else {
                nums[++slow]=nums[fast++];
                cnt=0;
            }
        }
      
        return slow+1;
    }
};
posted @ 2022-04-02 20:56  付玬熙  阅读(22)  评论(0编辑  收藏  举报