一、题目描述与要求
80. 删除有序数组中的重复项 II - 力扣(LeetCode)
题目描述
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例
示例1:
输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。
示例2:
输入:nums = [0,0,1,1,1,1,2,3,3]
输出:7, nums = [0,0,1,1,2,3,3]
解释:函数应返回新长度 length = 7, 并且原数组的前五个元素被修改为 0, 0, 1, 1, 2, 3, 3 。 不需要考虑数组中超出新长度后面的元素。
提示
1 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums
已按升序排列
二、解题思路
总的思路:
先分析题目,题目说给定一个有序的数组,要求我们删除数组中出现次数大于两次的元素,并且只能够在原数组上进行修改,不能借用额外的数组,最后要求返回数组的新长度。
首先我们要删除数组中出现次数大于两次的元素,那就必须遍历整个数组,而如何找出出现次数大于两次的元素并且将其删除呢?最简单的想法就是将每个元素依次与后面的元素进行比较,然后统计次数,在比较的同时发现出现次数大于2就进行修改,但这一实现方法需要运用到嵌套循环,空间复杂度较高,而且实现也较为复杂。因而我们可以想到“双指针”的方法,也就是利用两个指针来实现对数组元素的遍历还有更新。因而我们可以定义两个变量,一个用来遍历数组,一个用来记录更新后数组的长度以及对数组进行更新。
然后我们来分析数组的情况,对于数组元素个数小于等于2的则可以直接返回数组长度。因为我们需要保证每个元素只出现两次,因而我们对元素进行比较应当是将第一个与第三个元素进行比较(因为题目说是有序数组),如果相等的话就代表当前元素出现次数大于2,因而将遍历指针往后移动,找到与前面元素不相等的元素,然后对其进行赋值,然后更新修改后的数组长度(也就是更新指针向后移动一位)。因而两个指针的初始值都是2,而每次比较都是用遍历指针指向的元素与更新指针所指向的元素的前面第二个元素(从右往左数第二个)进行比较。
【以下举一个示例进行分析两个指针的变化】
具体步骤:
①判断数组长度是否大于2
②初始化两个指针
③遍历数组并进行更新
④返回更新后的数组长度
三、具体代码【C语言】
int removeDuplicates(int* nums, int numsSize){
if(numsSize<=2) return numsSize;
int left = 2, right = 2;//有序数组,每个元素只出现两次,因此right从下标2开始遍历
//while的执行条件为right<numsSize,即未遍历完数组
while (right < numsSize) {
//比较当前位置的元素与自己前面第二个元素是否相等
//如果相等则需要继续向后面找新的元素替代掉当前位置的元素
//如果不相等则将此时right所指向的元素赋值给left所指向的元素
//left就是修改后的数组长度,而right是用来遍历访问整个数组的
if (nums[left - 2] != nums[right]) {
nums[left] = nums[right];
++left;
}
++right;
}
return left;
}