题目描述
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定数组 nums = [1,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。
你不需要考虑数组中超出新长度后面的元素
双指针法:
算法
数组完成排序后,我们可以放置两个指针 i 和 j,其中 i是慢指针,而 j 是快指针。只要 nums[i] == nums[j],我们就增加 j 以跳过重复项。
当我们遇到 nums[i] != nums[j]时,跳过重复项的运行已经结束,因此我们必须把它nums[j]的值复制到 nums[i+1] 。然后递增 i,接着我们将再次重复相同的过程,直到 j 到达数组的末尾为止。
//[1,1,2] 结果是 [1, 2] i是下标从0开始所以返回i+1为数组长度
public int removeDuplicates(int[] nums){
int i = 0;
for(int j = 1; j < nums.length; j++){
if(nums[i] != nums[j]) {
i++;
nums[i] = nums[j];
}
}
return i + 1;
}
复杂度分析
时间复杂度:O(n), 假设数组的长度是 n,那么 i 和 j 分别最多遍历 n 步。
空间复杂度:O(1).
相似题目
27 移除元素
题目描述
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例 1:
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
双指针
既然问题要求我们就地删除给定值的所有元素,我们就必须用 O(1) 的额外空间来处理它。如何解决?我们可以保留两个指针 i 和 j,其中 i 是慢指针,j 是快指针。
算法
当 nums[j]与给定的值相等时,递增 j 以跳过该元素。只要 nums[j] != val我们就复制 nums[j]到nums[i] 并同时递增两个索引。重复这一过程,直到 j 到达数组的末尾,该数组的新长度为 i。
[3,2,2,3], val = 3, 结果[2,2]长度为2 所以返回是i
public int removeElement(int[] nums, int val){
int i = 0;
for(int j = 0; j < nums.length;j++){
if(array[j] != val){
array[i++] = array[j];
}
}
return i;
}
80 删除排序数组中的重复项 II
题目描述
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素最多出现两次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定 nums = [1,1,1,2,2,3],
函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。
你不需要考虑数组中超出新长度后面的元素。
示例 2:
给定 nums = [0,0,1,1,1,1,2,3,3],
函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。
你不需要考虑数组中超出新长度后面的元素。
public int removeDuplicates(int[] nums) {
int j = 0;
int count = 1;
for(int i = 1; i < nums.length; i++){
if(nums[i] == nums[j]){
count++;
if(i == nums.length - 1){
// 如果不写这一步 那么[0,0,1,1,1,1,2,3,3]输出结果是[0,0,1,1,2,3],而正确答案是[0,0,1,1,2,3,3],因为当不写是i = 8时,由于j = 5且num[j] = 3,即[0,0,1,1,2,3]此时count = 2且num[j] == num[i] == 3;直接返回j+1为6个元素显然是错误的,还应该把最后一位赋值,再返回长度j+1,因为j是从0开始的,所以数组长度为j+1;
nums[++j] = nums[i];
return j + 1;
}
}else{
if(count >= 2){
j += 2;
}else{
j+= 1;
}
count = 1;
nums[j] = nums[i];
// 如果不写这一步 那么[1,1,1,1,2,2,3]输出结果是[1,1,2,1,3],而正确答案是[1,1,2,2,3],因为当i 为 4时,count 为 4 (因为是4个1)且 j += 2,nums[j] = nums[i];执行完之后为[1,1,2,1,2,2,3]显然j为3时的1是应该垃圾数据,下次当count大于2时,又跳过了2个然后赋值为3记[1,1,2,1,3]所以要把从j到i直接的都变为当前i所在的值,才会有正确的结果
int k = j;
while(k < i){
nums[++k] = nums[i];
}
}
}
return j+1;
}
public int[] removeElement(int[] arr, int removedIndex){
// removedIndex = 3 arr = [0,0,0,1,2,3,4] => [0,0,1,2,3,4]
// 重写给定下标index的元素,移动下标index右边的所有元素到其前一个位置
for(int i = removedIndex + 1;i < arr.length;i++){
arr[i-1] = arr[i];
}
return arr;
}
public int removeDuplicates(int[] nums){
// [1,1,1,1,2,3,4]
int i = 1, count = 1, length = nums.length;
while(i < length) {
if(nums[i-1] == nums[i]){
count++;
if(count > 2){
this.removeElement(nums,i);
// 如果当前元素是重复的,增加count,当count超过两个的时候,这个是一个不想要的重复元素,我们从数组中移除
我们已经减少了数组Index的值为保持一致,i和length都要减减
i--;
length--;
}
}else{
// 重置不一样元素的count
count=1;
}
//移动到下一个数组元素
i++;
}
return i;
}