题目:
给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 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。
你不需要考虑数组中超出新长度后面的元素。
解答:
首先是自己的解答:
根据提示,使用双指针,也叫快慢指针,index1从首部移动, index2向后移动直到值与index1不同,则将 index2及之后的元素移动到index1+1的位置,重复直至index2抵达末位,然后返回的长度为:index1+1,因为index1是索引,比当前不重复元素少一。
代码如下:
//26. 删除排序数组中的重复项 //原地删除重复元素,并且返回结果的长度int //双指针 int removeDuplicates(vector<int>& nums) { if (nums.size() < 2) return nums.size(); //排序 sort(nums.begin(), nums.begin() + nums.size()); int idx1 = 0, idx2 = 1; while (idx2 < nums.size()) { while (idx2 < nums.size() && nums[idx1] == nums[idx2]) idx2++; if (idx2 == nums.size()) return idx1 + 1; for (int i = idx1+1; i < idx2; i++) { nums[i] = nums[idx2]; } //test for (auto val : nums) { cout << val << " "; } cout << endl; idx1++; idx2++; } return idx1 + 1; }
虽然提交后通过了,但是时间、空间效率很差。
看解答后,发现只要把index2处不重复的元素复制到index1+1即可,减少元素的移动次数,代码如下:
int removeDuplicates(vector<int>& nums) { if (nums.size() < 2) return nums.size(); //sort sort(nums.begin(), nums.begin() + nums.size()); int idx1 = 0, idx2 = 1; while (idx2 < nums.size()) { if (nums.at(idx1) != nums.at(idx2)) { //如果不等,把idx2的元素放到idx1++的位置 idx1++; nums[idx1] = nums[idx2]; } //如果idx2 与 idx1 相等,则j++ idx2++; } return idx1 + 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。
注意这五个元素可为任意顺序。
你不需要考虑数组中超出新长度后面的元素。
解答:
27题与26题类似,放到一起写。先自己写的代码,使用两个index在数组中移动,index找到第一个==val的值,然后index2找到后面不等于val的值,然后使用一个变量交换这两个位置的值“:
int removeElement(vector<int>& nums, int val) { if (nums.size() == 0) return 0; else if (nums.size() == 1 && nums[0] != val) return nums.size(); int idx1 = 0, idx2 = 1; int tmp = 0; while (idx2 < nums.size()) { while (idx1 < nums.size() && nums[idx1] != val) { idx1++; idx2++; } if (idx1 == nums.size() || idx2 >= nums.size()) break; if (nums[idx2] == val) { idx2++; continue; } //此时,idx1=val,idx2++找到一个不等的元素 tmp = nums[idx2]; nums[idx2] = nums[idx1]; nums[idx1] = tmp; idx1++; idx2 = idx1 + 1; } return idx1; }
解答的代码:真tm简洁,自己写的就是一坨,解答中的代码可以在num[i]=num[j]之前加个判断,当i == j时赋值这步可以跳过,减少操作。
public int removeElement(int[] nums, int val) { int i = 0; for (int j = 0; j < nums.length; j++) { if (nums[j] != val) { nums[i] = nums[j]; i++; } } return i; }