题目介绍
输入:nums={0,0,1,1,2,3,3}
输出:4,nums={0,1,2,3,}
解释:函数应该返回新的长度4,并且原数组nums的前四个元素被修改为0,1,2,3。同时不需要考虑数组中超出新长度后面的元素。
方法:双指针
完整代码展示
#include<iostream>
#include<vector>
using namespace std;
class Solution
{
public:
int removeDuplicate(vector<int>& nums)
{
int n = nums.size();
if (n == 0)
{
return 0;
}
int fast = 1, slow = 1;
while (fast < n)
{
if (nums[fast] != nums[fast-1])
{
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
};
int main()
{
vector<int>nums = { 0,0,1,1,2,3,3 };
Solution find;
int newSize = find.removeDuplicate(nums);
cout << "新数组的长度:" << newSize << endl;
cout << "新数组的元素:";
for (int i = 0; i < newSize; ++i)
{
cout << nums[i] << " ";
}
cout << endl;
return 0;
}
核心原理演示
输入:nums={0,0,1,1,2,3,3}
输出:4,nums={0,1,2,3,}
总而言之:while循环中在图中的表现可以理解为,当fast与fast-1
- 相等时,fast与fast-1都指向自己现在指向的数组元素的下一项。
- 不相等时,先把slow指向的元素用fast指向的元素替换掉,后slow指向数组的下一项,最后再执行 相等时的操作。
即,每一轮循环fast都要“前进一步”也就是说fast与slow两者虽然起始时都指向同一位置,由于fast“走得更快”最终fast势必会在slow的前面。所以:
- fast指针负责遍历整个向量,
寻找
不重复的元素和可以保留的重复元素- slow指针负责
记录
不重复元素和可以记录的重复元素的位置
故而:
while (fast < n)
,fast的值作为循环(整个遍历过程)结束的标志。return slow;
,slow的值作为数组nums中元素的种类个数。
代码片段解释
片段一:
if (nums[fast] != nums[fast-1])
{
nums[slow] = nums[fast];
++slow;
}
slow的值之所以可以作为数组nums中元素的种类个数,最终归咎在fast指针上。因为fast指针并不是简简单单的遍历了数组的某一项,就可以进行++slow;的,而是在每次遍历时都要先进行
nums[fast] != nums[fast-1]
判断,再去判断是否进行++slow,这个判断条件
再结合本题数组的限制条件是:“有序数组”
两者构成的绝美组合便可以保证:满足判断条件nums[fast] != nums[fast-1]
的原因一定是因为在遍历过程中出现了新的一种元素。从而避免了也可能是在遍历“无序数组”时出现了之前已经出现过的重复项所导致的判断条件被满足的可能。继而
nums[slow] = nums[fast];
将遍历到的新的一种元素添加到记录的位置处。同时
++slow;
标志着新的一种元素数量+1