力扣每日一题(2024.06.21):移除重复元素II

96 阅读2分钟

题目: 给你一个有序数组 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个,如果超过,则将数组前移,for循环结束标志为快指针=数组长度-每次前移的位数。

代码实现:

public static int removeDuplicates(int[] nums) {

    // 使用n记录fast指针的数出现的次数, offset代表每次少走的路,如果数组前移了offset,则offset之后不用再遍历
    int slow,fast,n=1,offset=0;

    // 循环结束标志为fast指针走到数组中所有数字最多出现两次的数组长度
    for (fast = 1, slow = 1; fast < nums.length-offset; fast++) {

        if(nums[fast]==nums[fast-1]){
            n++;

            if(n==2){
                slow++;
            }

        }else{
            // 如果当前位置的数与前一位不同时,且出现次数>2时,则当前位置及后面的数需要向前移n位置
            if(n>2){
                for (int i = fast,j=slow; i < nums.length; i++,j++) {
                    nums[j]=nums[i];
                }

                // n-2代表如果当前数有大于两个时,则偏移时需要保留2个
                offset = offset + (n - 2);
                fast = slow;
            }

            // n用完归位
            n=1;
            slow++;
        }

    }

    return slow;
}

这种实现方式比较耗时,另外学习一下力扣大佬的实现思路,也是用的快慢指针,每次循环,判断快指针与慢指针-2所指的数是否相同,如果不相同,则代表,fast位置的数需要前移,代码如下:我只想说大佬牛比!

public static int removeDuplicates3(int[] nums) {
    int len = nums.length;

    if(len <= 2){
        return len;
    }

    int slow = 2; int fast = 2;

    while(fast < len){
        if(nums[slow - 2] != nums[fast]){
            nums[slow] = nums[fast];
            slow++;
        }
        fast++;
    }
    return slow;
}