给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。
给定 nums = [0,0,1,1,1,2,2,3,3,4],
函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4。
你不需要考虑数组中超出新长度后面的元素。
为什么返回数值是整数,但输出的答案是数组呢?
请注意,输入数组是以“引用”方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。
你可以想象内部操作如下:
// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);
// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。
for (int i = 0; i < len; i++) {
print(nums[i]);
}
//第一种
int removeDuplicates(int* nums, int numsSize)
{
for(int i = 0; i < numsSize - 1; ++i)
{
if(nums[i] == nums[i+1])
{
for(int j = i; j < numsSize - 1; ++j)
{
nums[j] = nums[j + 1];
}
numsSize -= 1;
i--;
}
}
return numsSize;
}
//说明:
//这是最一般的做法,外层循环用于遍历数组以判断相邻两个元素是否相同,
//内层循环用于遍历“后续元素”从而把它们依次往前移动一个位置,为了应
//对多个相邻元素都相同的情况,在进行完内循环之后要进行【i–】的操作,
//从而抵消外循环中【i++】的操作。
//第二种
int removeDuplicates(int* nums, int numsSize)
{
int i = 0, tail = 0;
if(0 == numsSize)
return 0;
for(; i < numsSize - 1; i++)
if(nums[i] != nums[i + 1])
nums[tail++] = nums[i];//等价于nums[tail] = nums[i];tail++;
nums[tail] = nums[i];//前面一定要进行numsSize是否为0的判断,否则当numsSize为0时会产生缓冲区溢出的错误
return tail + 1;
}
//说明:
//tail指向新数组的尾部位置,虚位以待那个“不同的数”的到来。
//i用于遍历数组,以判断相邻两数是否相同,如果不同,就把i指
//向的数保存到tail指向的位置;如果相同,则什么都不做,i继
//续往后走,直到遇见两个不同的数,此前i已经遇到若干个相同的
//数了,现在要把i指向的、同时也是这若干个相同的数中最后一个
//数保存到tail指向的位置。然后i继续往后走并继续进行以上的判
//断和操作,当i走到整个数组的末尾时,它就走到尽头了,此时要
//把它指向的数保存到tail指向的位置。
//第三种(1)
int removeDuplicates(int* nums, int numsSize)
{
int i = 1, tail = 0, same = 0;
while(i < numsSize)
{
if(nums[tail] != nums[i])
nums[++tail] = nums[i];
else
++same;
++i;
}
return numsSize - same;
}
//第三种(2)
int removeDuplicates(int* nums, int numsSize)
{
int i = 1, tail = 0;
if(0 == numsSize)
return 0;
for(; i < numsSize; ++i)
if(nums[tail] != nums[i])
nums[++tail] = nums[i];
return tail + 1;
}
//说明:tail指向新数组的尾部,当nums数组不为空时,它的第一个元素肯定要加
//入新数组的,所以i从下标1开始往后走,当它遇到一个与tail指向的元素不同的数
//时,就先让tail往后走一步,并且把那个数保存到tail现在指向的新位置,当它碰到
//一个与tail指向的元素相同的数时,就什么也不做,接着往后找,直到走到nums数
//组的尽头。
//以上两种写法,一种要判断numsSize是否为0,一种不需要判断,是因为最后返回
//值的写法不同。
class Solution {
public:
int removeDuplicates(vector<int>& nums)
{
int i = 1, tail =0;
if(nums.empty())
return 0;
for(; i < nums.size(); ++i)
if(nums[tail] != nums[i])
nums[++tail] = nums[i];
return tail + 1;
}
};
//说明:
//本来想用迭代器,但是发现用了比不用还麻烦,于是放弃了,
//将前面的C语言程序稍稍改写一下就行了。
在三种解题思路中,我最喜欢第三种思路,不仅很简单,而且时间复杂度低。