刷题系列之80. 删除有序数组中的重复项 II

168 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情

前言

题目来源

leetcode.cn/leetbook/re…

题目介绍

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

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

输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。

题目分析

这道题跟前面的题目类似,已知数组,删除重复的元素,但是元素最多可以出现2次,最后返回新数组长度。根据示意,如果有个元素重复了三次,那么我们要删除一个,保留2个。如果只有2个那么不用删除。

题目解答

class Solution {
    public int removeDuplicates(int[] nums) {
    int len = 0;
    for(int i = 0; i < nums.length; i++){
        if(len < 2 || nums[i] != nums[len-2]){
            nums[len++] = nums[i];
        }
    }
    return len;
  }    
}

这道题解法参考了评论区的大哥的,很巧妙。既然相同数字最多只能保存两个,又因为数组有序,相同的数字必然连续,所以只需判断数字与它相隔前两个位置的数字是否相同,相同则不存,不同才存。

因此如果数组长度小于2的,那么直接赋值就好了。

当从第三个元素开始,就开始判断与前2个位置的元素是否相等,比如nums[3]与nums[1]比较。如果不相等,那么给下标变量元素赋值当前元素,依次类推,下标变量最后的值结果就是新数组的长度。

image.png

image.png

官方答案验证

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

官方的做法跟之前类似,因为给定数组是有序的,所以相同元素必然连续。我们可以使用双指针解决本题,遍历数组检查每一个元素是否应该被保留,如果应该被保留,就将其移动到指定位置。

具体地,我们定义两个指针 slow 和 fast 分别为慢指针和快指针,其中慢指针表示处理出的数组的长度,快指针表示已经检查过的数组的长度,即 nums[fast] 表示待检查的第一个元素,nums[slow−1] 为上一个应该被保留的元素所移动到的指定位置。

image.png

总结

删除有序数组的元素题目,已经做了2题了,大致思路都类似,坚持总结。