算法题每日一练---第99天:删除有序数组中的重复项

999 阅读1分钟

一、问题描述

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

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

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

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

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

题目链接:删除有序数组中的重复项

二、题目要求

样例 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 。
不需要考虑数组中超出新长度后面的元素。

考察

1.哈希表、双指针
2.建议用时15~25min

三、问题分析

1.暴力哈希

这一题只允许在原有的数组修改,空间复杂度O(1)。一开始没用双指针,直接暴力哈希,搞了一下。

我们从前向后遍历数组元素,未在哈希表出现过的元素,哈希表计数++下标+1,不作删除处理。

在哈希表中出现的元素,直接调用erase删除就行。

2.双指针

暴力哈希耗时太长,后来发现题目不要求删除数组内部的重复元素,所以我们可以将符合条件的元素排到前面就行,最终返回一个符合条件的数组长度。

3.png

定义一个指针j用来存储符合条件的数组元素长度,初始化为1,第一个元素肯定不重复。

定义一个指针i用来判断当前的元素是否和之前元素重复,不重复证明找到了,赋值给j指向的下标。 重复,向下遍历,直到末尾。

四、编码实现

1.暴力哈希

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int i=0;
        map<int,int>m;//哈希计数
        while(i<nums.size())
        {
            if(m[nums[i]])
                nums.erase(nums.begin()+i);//删除
            else
            {
                m[nums[i]]++;
                i++;
            }
        }
        return nums.size();//返回结果
    }
};

2.双指针

class Solution {
public:
    int removeDuplicates(vector<int>& nums) {
        int i,j,n=nums.size();//初始化
        if(n<2) return n;//判断初始数组大小
        j=1;
        for(i=1;i<nums.size();i++)//指针i遍历
        {
            if(nums[i]!=nums[i-1])//不相等
                nums[j++]=nums[i];//存储结果
        }
        return j;   
    }
};

五、测试结果

1.png

2.png

第一种是哈希暴力做的,和第二种内存消耗差不多,但明显执行用时比双指针差了很多,双指针下面陆续出几道题目练练手。

19.png