leetcode 第80题:删除有序数组中的重复项II(原题为26题)
要求:
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
示例:
输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]
解释:函数应返回新长度 length = 5, 并且原数组的前五个元素被修改为 1, 1, 2, 2, 3 。 不需要考虑数组中超出新长度后面的元素。
输入: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 。 不需要考虑数组中超出新长度后面的元素。
我写的版本:通过一个 flag 计数,记录重复元素数量超过2的
public static int removeDuplicates2_2(int[] nums) {
if(nums == null || nums.length <= 1 ){
return nums.length;
}
int j = 0;
int flag = 1;
for(int i=1; i<nums.length;i++){
if(nums[j] != nums[i]){
nums[++j] = nums[i];
flag=1;
}else if(nums[j] == nums[i]){
// 元素如果相等,Flag++
// 当 Flag 大于2时就已经达到重复的上限
flag++;
if(flag <= 2){
nums[++j] = nums[i];
}
}
}
return j+1; // 作为数组的右边界(开区间),范围为:[0,j+1) 不包括 j+1
}
大佬的版本:巧妙的使用了一个长度为k+1的滑动窗口,每次新元素都会和这个窗口的第一个元素(i-k)
位置进行比较,如果新元素不大于窗口的第一个元素,说明重复元素超过了要求的上限。
而窗口的最后一个元素是就是 i
位置,也是当前循环需要操作的位置。
// 改进版本: 将每个元素的重复个数上限扩展为k。
public static int removeDuplicates4(int[] nums,int k){
int i = 0;
for (int n : nums)
// i<k:单个重复项最大为k,无论前k个元素是什么都是满足条件(在序列有序的情况下)。
if (i < k || n > nums[i-k])
nums[i++] = n;
return i;
}