执行速度0ms,题目重点是原地删除以及只可以使用额外的O(1)空间。所以按照平常的新旧数组复制是不可行的。因此想到了利用双指针(fast,slow)利用元素交换下标的或者覆盖的方式进行删除。
双指针过程如下图所示:
图中实例: nums = 0 0 1 1 1 1 2 3 3
- 首先找出第一个出现符合重复条件的元素,也就是实例下标4的元素1
- 利用count进行计数,当temp记录当前数,fast进行遍历后续的数
- 当fast遇到与temp不相同的元素时,更新temp为新的元素,count置位0
- fast继续前移,直到找到属于重复项元素的第一个下标
for (fast = 0; fast < nums.length; fast++) {
if (nums[fast] == temp) {
count++;
}
//如果大于2,则break跳出循环
if (count > 2) {
break;
}
//如果没大于2,且count=0,则继续
if (nums[fast] != temp) {
temp= nums[fast];
count = 1;
}
}
- 通过下标4的元素开始执行我们的置换,主要是以下几步:
- 开始置换,只要fast对应的位置和slow对应的 前2个位置(刚好符合最极限的允许2个相同元素的条件),即slow -2 不相同,
则可以认为fast所指的位置是符合要求的数字, - 把fast所指数插入到slow所指的位置中,slow++(后移)
- 因为slow至少从nums第三个元素起,所以不会出现 slow-2越界
- 其他情况则fast后移
for(fast=slow+1;fast<nums.length;fast++){
if(nums[fast] != nums[slow-2]){
nums[slow++] = nums[fast];
}
}
最后只需要返回slow的下标位置,就是题目所需要的删除后的数组长度啦
全部代码:
public int removeDuplicates(int[] nums) {
int slow, fast;
int count = 0;
int temp = nums[0];
//快指针先走
for (fast = 0; fast < nums.length; fast++) {
if (nums[fast] == temp) {
count++;
}
//如果大于2,则break跳出循环
if (count > 2) {
break;
}
//如果没大于2,且count=0,则继续
if (nums[fast] != temp) {
temp= nums[fast];
count = 1;
}
}
//slow指向当前fast指针所在得位置,然后fast指针继续向前
slow = fast;
//开始置换
/**
* 开始置换,只要fast对应的位置和slow对应的 前2个位置(因为一个元素可以重复两次),
* 1. 即slow -2 不相同,则可以认为fast所指的位置是符合要求的数字,
* 2. 插入到slow所指的位置中,slow++(后移)
* 3. 因为slow至少从nums第三个元素起,所以不会出现 slow-2越界
*/
for(fast=slow+1;fast<nums.length;fast++){
if(nums[fast] != nums[slow-2]){
nums[slow++] = nums[fast];
}
}
return slow;
}