leetcode_80. 删除有序数组中的重复项 II

leetcode_80. 删除有序数组中的重复项 II

leetcode链接

题目描述

给你一个有序数组 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 已按升序排列

题解

方法一: 普通双指针

使用双指针的解法可以参考leetcode_26. 删除有序数组中的重复项. 思路基本类似, 唯一的区别就是重复超过两次的元素我们要保留两次.

此时, 我们只需要增加一个变量t来记录j指针遍历到的重复元素都数量, 如果大于等于2, 那么就让i指针先将自身的值向后复制一下, 同时i指针也向后移动一位 nums[++i] = nums[i];, 然后再像普通的去重算法一样执行nums[++i] = nums[j];即可.

值得注意的是在c++中, nums[++i] = nums[i]是没问题的, 但是在java中, 这句代码只会让i自增, 并不能将nums[i]赋值给nums[i+1]. 具体原因我并不了解, 欢迎大家在评论区讨论.

最后再处理一下边界问题, 当数组中的最后一个元素是重复元素时, 还没来得及给他保留两份循环就结束了,

java

class Solution {
    public int removeDuplicates(int[] nums) {
        int i = 0, j = 0, t = 0;
        while (j < nums.length) {
            if (nums[i] != nums[j]) {
                if (t > 1) {
                    nums[i+1] = nums[i];
                    i++;
                }
                nums[++i] = nums[j];
                t = 1;
            } else {
                t++;
            }
            j++;
        }
        if (t > 1) {
            nums[++i] = nums[j-1];
        }
        return i+1;
    }
}

C++

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int i = 0, j = 0, t = 0;
        while (j < nums.size()) {
            if (nums[i] != nums[j]) {
                if (t > 1) {
                    nums[++i] = nums[i];
                }
                nums[++i] = nums[j];
                t = 1;
            } else {
                t++;
            }
            j++;
        }
        if (t > 1) {
            nums[++i] = nums[j-1];
        }
        return i+1;
    }
};

方法二: 更高效的双指针

我们还是用j指针区遍历数组, 用i指针去记录有效数组的边界, 但不同的是, 每次要判断nums[i-2] != nums[j], 如果满足就把j指针指向的元素覆盖的i指针所在的位置, 然后i指针向后移动一位.

这种算法的原理也是去判断重复元素都数量有没有超过两个. 如果nums[i-2] != nums[j]这个条件不满足, 那么就说明重复的元素已经保留了两个了, 所以之后再遇到就不会再保留了, 于是j指针直接后移. 如果条件满足, 那么就说明重复的保留的重复的元素的数量还不够两个, 于是当前j指针指向的值也要保留(nums[++i] = nums[j]).

OK, 上代码

java

class Solution {
    public int removeDuplicates(int[] nums) {
        int n = nums.length;
        if (n < 3) return n;
        int i = 2, j = 2;
        while (j < n) {
            if (nums[i - 2] != nums[j]) {
                nums[i++] = nums[j];
            }
            j++;
        }
        return i;
    }
}

C++

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int n = nums.size();
        if (n < 3) return n;
        int i = 2, j = 2;
        while (j < n) {
            if (nums[i - 2] != nums[j]) {
                nums[i++] = nums[j];
            }
            j++;
        }
        return i;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值