一、问题描述
给你一个 升序排列 的数组 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.双指针
暴力哈希耗时
太长,后来发现题目不要求删除数组内部的重复元素,所以我们可以将符合条件的元素排到前面就行,最终返回一个符合条件的数组长度。
定义一个指针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;
}
};
五、测试结果
第一种是哈希暴力做的,和第二种内存消耗差不多,但明显执行用时比双指针差了很多,双指针下面陆续出几道题目练练手。