【LeetCode】【C++】27. 移除元素 80.删除有序数组中的重复项Ⅱ
27. 移除元素
题目描述
详见LeetCode 27. 移除元素。
这是一道特别水的题,但是我第一时间没有想到正确的解答思路。
题目描述可以简述为,给定数组nums和元素val,原地删除nums中等于val的元素,并返回nums中不等于val元素的个数。
思路
一开始我确实想到了要使用双指针来做,但是我错误的将第二个指针设置到了nums的尾部,想要将等于val的元素直接和尾部的元素进行交换,这个思路有一个很大的问题在于,尾部的元素也可能等于val。
正确的双指针思路是,设置两个双指针,均从头开始对nums进行遍历,记作left和right。
如果nums[right] != val
,意味着可以令nums[left] = nums[right]
,并将两个指针同时右移,否则只移动right
指针。
最后left
的值就是nums中不等于val的个数。
class Solution {
public:int removeElement(vector<int>& nums, int val) {int left = 0;int n = nums.size();for(int right = 0; right < n; right ++) {if(nums[right] != val) {nums[left] = nums[right];left ++;}}return left;}
};
80.删除有序数组中的重复项Ⅱ
题目描述
详见leetcode原题目。
与这道题相似的是26. 删除有序数组中的重复项,这两道题与27. 移除元素类似,都涉及到原地对数组进行操作,都可以使用双指针算法来解决。
这道题目可以简单描述为,给定一个单调不减的数组,请原地删除数组当中的元素,使得重复的元素不超过两个,并返回最终数组的长度。
思路
自己还是太菜了,菜就要多练,参考了LeetCode的题解才想明白。
这道题仍然使用双指针算法来求解,但是不需要插旗来检查当前保留的元素是否超过两个。
需要注意的是对题目的性质进行仔细考察,仔细观察后可以发现,当前仅当当前位置i
与i-2
的元素不相同时,才需要对该位置的元素进行保留操作,这也一定程度上利用了数组的有序性。
因此可以设置两个指针,分别是慢指针slow和快指针fast,使用慢指针slow来对数组当中的元素进行移动,使用快指针fast来对整个数组进行检查。
将这两个指针均初始化为2
,如果nums[slow - 2] != nums[fast]
,说明此时要对数组当中的元素进行移动,即令nums[slow++] = nums[fast]
。
上述语句看似非常简单,它为什么是合理的呢?考虑nums[slow - 1]
,如果它与nums[slow - 2]
是相等的,注意题目给定的条件,至多保留两个相同的元素,我们无需对它进行操作。只有当nums[slow - 2]
与nums[fast]
不相等的时候,才需要将fast指针处的元素移动到slow指针处。
举个例子,假设有数组[1, 1, 2, 2, 2, 3, 3, 3, 3, 3]
,初始化的slow和fast都是2,即指向数组的第三个位置。初始化为2的原因是不需要考虑0和1两个位置的元素,而这必然是满足题意的,可以保留。对于fast == 2
这个位置,nums[slow - 2]
的值是1,与2不等,可以将fast位置的元素移动到slow。此时fast继续移动,移动到下标为3的位置时,nums[slow-2]
的值仍然是1,与2不相等,仍然可以将fast位置的元素移动到slow。注意此时slow的值为4,因为保留了两个值为2的元素,slow此时指向的是下一个可能要将元素移动过来的位置。
然而,继续移动fast可以发现,当fast移动到下标为4的位置时,nums[slow-2]
的值是2,此时fast和slow - 2指向的元素相等了,由于新数组当中的元素重复的次数不能超过2,所以此时不能将fast位置的元素移动到slow。
继续移动fast至下标为5的位置,此时fast位置的元素为3,slow-2位置的元素为2,slow-1位置的元素也是2,可以将fast位置的元素移动到slow。
代码如下:
class Solution {
public:int removeDuplicates(vector<int>& nums) {int n = nums.size();if(n <= 2) {return n;}int slow = 2, fast = 2;while(fast < n) {if(nums[slow - 2] != nums[fast]) {nums[slow ++] = nums[fast];}fast ++;}return slow;}
};