问题描述:
给定一个排序数组,删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
示例:
给定 nums = [0,0,1,1,1,2,2,3,3,4],函数返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 [0, 1, 2, 3, 4]。可以不考虑数组中超出新长度后面的元素。
思路:
// 最直观的思路是这样的:int len = removeDuplicates(nums);// 在函数里修改输入数组对于调用者是可见的。// 根据你的函数返回的长度, 它会打印出数组中该长度范围内的所有元素。for (int i = 0; i < len; i++) { print(nums[i]);}
我们可以使用快慢指针的方法
数组完成排序后,我们可以放置两个指针 i 和 j,其中 i 是慢指针,而 j 是快指针。只要 nums[i] = nums[j],我们就增加 j 以跳过重复项。
当我们遇到 nums[j] !=nums[i] 时,跳过重复项的运行已经结束,因此我们必须把它(nums[j])的值复制到 nums[i + 1]。然后递增 i,接着我们将再次重复相同的过程,直到 j 到达数组的末尾为止。
时间复杂度分析
O(n),假设数组的长度是 n,那么 i 和 j 分别最多遍历 n 步。
代码实现
int removeDuplicates(vector<int>& nums) { //此处缺少判断0长度的数组 int i = 0; //慢指针指向数组头 for (int j = 1; j < nums.size(); ++j) { if (nums[i] != nums[j]) { //如果相等,慢指针就不动,快指针移动 nums[++i] = nums[j]; //如果不等,慢指针前进,覆盖 //此处如果先判断++i !=j 再复制,也可以,其实判断也是需要时间的 } } return i+1;}
其实,也可以用unique函数,unique函数通常和erase函数一起使用,来达到删除重复元素的目的。
int removeDuplicates(vector<int>& nums) { nums.erase(unique(nums.begin(), nums.end()), nums.end()); return nums.size(); }
如果不需要考虑最后的元素,可以直接使用unique。
int removeDuplicates(vector<int>& nums) { return unique(nums.begin(), nums.end()) - nums.begin() - 1; //也可以使用distance(it1, it2)来判断两者之间的距离 }
其实unique函数的内部实现和我们上面的代码是一样的。
iterator My_Unique(iterator first, iterator last){ if (first==last) return last; iterator result = first; while (++first != last) { if (!(*result == *first)) *(++result)=*first; } return ++result;}
需要注意的是,单纯的使用unique函数的话,容器的长度并没有发生变化,只是元素的位置发生了变化。unique函数通常和erase函数一起使用,来达到删除重复元素的目的。
iterator unique(iterator it_1,iterator it_2,bool MyFunc);
unique函数可以自定义一个判重自定义函数,类似sort函数里面的。
bool cmp(int a, int b){ return a > b;}
有什么问题,可以给留言或者扫码加微信群讨论。