【刷题笔记】删除有序数组中的重复项

目录

一、删除有序数组中的重复项

题目链接:

题目描述:

题目解析:

解题代码:

二、 删除有序数组中的重复项 II

题目链接:

题目描述:

题目解析:

解题代码:


一、删除有序数组中的重复项

题目链接:

        删除有序数组中的重复项

题目描述:

        给你一个 升序排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。

由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。

将最终结果插入 nums 的前 k 个位置后返回 k 。

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

示例1:

        输入:nums = [1, 1, 2]

        输出:2,nums = [1, 2, _]

        解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

示例2:

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

题目解析:

        首先明确题目要求,使用的是O1的额外空间,意思就是需要我们原地修改输入的数组。由于是升序排序,所以我们可以确定的是重复的元素一定是挨着一起的。并且题目中也提示了可以不用修改原数组的长度,所以不用真的“删除”。

        既然是原地,不妨按照类似于双指针的方式,利用一个指针指向删除后数组的当前最后一个下标,而另外的指针遍历原本的数组。(注意这两个数组一定是一个数组)当这两个指针指向的元素不等的时候,我们就进行第一个指针++移动到下一个位置进行赋值;如果相等,也就是第二个指针往后走即可。(因为第一个指针指向的位置 <= 第二个指针指向的位置,所以在同一个数组上操作没有任何问题)。

        当然,除了自己写之外,也可以利用STL库中的方法进行解答。distance-用于计算两个迭代器之间的距离(用作返回),unique-用于删除相隔之间重复的元素(删除数组必须是有序的)。

解题代码:

        方法1、双指针法

class Solution {
public:
    int removeDuplicates(vector& nums) {
        int index = 0;
        for (int i = 1; i < nums.size(); ++i)
        {
            if (nums[index] != nums[i]) nums[++index] = nums[i];
        }
        return index + 1;
    }
};

        方法2、STL库法

class Solution {
public:
    int removeDuplicates(vector& nums) {
        return distance(nums.begin(), unique(nums.begin(), nums.end()));
    }
};

二、 删除有序数组中的重复项 II

题目链接:

        删除有序数组中的重复项 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 。 不需要考虑数组中超出新长度后面的元素。

题目解析:

        这个题和上一个题类似,只不过特别的就是如果此重复元素出现的次数大于2次是需要保留两个的。那么在之前的双指针操作的时候就需要一个条件进行约束。

        我们可以就基于上面的代码进行修改。

【刷题笔记】删除有序数组中的重复项_第1张图片

         假设第一个指针指向删除后的数组的当前待排序下标,而第二个指针也是遍历原本的数组(前两个可以跳过,因为是有序的,所以前面两个不管是否重复)。此时的约束条件就是第一个指针 - k (k == 2)不等于第二指针指向的元素即可。那么,此时就可以有效的将重复元素控制在两个以内。这样就可以扩展下来,-3.-4..... 就可以控制重复元素在3、4......个之内。

        当然,也可以不同采用上面的通用的方法。因为相同的重复元素只能保持两个,当重复的元素超过两个的时候,一定存在nums[i] == nums[i-1]&&nums[i] == nums[i+1]。超出2个有几个,就会有几个这样的条件。那么我们可以利用此限制条件跳过超过两个的重复元素,否则就添加到数组里面即可。

解题代码:

1、双指针解法

class Solution {
public:
    int removeDuplicates(vector& nums) {
        if (nums.size() <= 2) return nums.size();

        int index = 2;
        for (int i = 2; i < nums.size(); ++i)
        {
            if (nums[index - 2] != nums[i]) nums[index++] = nums[i];
        }

        return index;
    }
};

2、特殊条件限定

class Solution {
public:
    int removeDuplicates(vector& nums) {
        int n = nums.size();
        if (nums.size() <= 2) return n;
        int index = 0;
        for (int i = 0; i < n; ++i)
        {
            if (i > 0 && i < n - 1 && nums[i] == nums[i - 1] && nums[i] == nums[i + 1])
                continue;
            nums[index++] = nums[i];
        }
        return index;
    }
};

你可能感兴趣的:(刷题笔记,数据结构,c++,算法)