C 删除有序数组中重复项(力扣)

题目:

给你一个 非严格递增排列 的数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums 中唯一元素的个数。

考虑 nums 的唯一元素的数量为 k ,你需要做以下事情确保你的题解可以被通过:

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 
  • 输出与输入格式   
  • 输入:nums = [0,0,1,1,1,2,2,3,3,4]     输出:5, nums = [0,1,2,3,4]

解题思路:

思路一:我们可以创建一个nums1[1000]={nums[0]}用于存储唯一元素,for循环遍历数组,如果后面的元素和前面的元素不一样,代表找到不一样的重复元素元素的第一个,在把第一个赋值给nums1就的得到重复元素元素的第一个也就是唯一元素,接着count统计一下

int removeDuplicates(int* nums, int numsSize) {
    int nums1[10000]={nums[0]};
    int count=1;//统计唯一元素个数
    int j=1;//新数组的元素下标
    for(int i=1;i<numsSize;i++) {
        if(nums[i]!=nums[i-1]) {
            nums1[j++]=nums[i];//把唯一元素存储在nums1
            count++;//赋值成功代表唯一元素个数+1
        }
    }
    //因为题目要求更改nums数组
    //所以再把nums1赋值给nums
    for(int k=0;k<count;k++) {
        nums[k]=nums1[k];
    }
    return count;
}

时间复杂度O(N),但空间复杂度是O(N),空间浪费太多

方法二:双指针

用i代表不确定元素的位置(意思就是nums[i]不知道是nums[i-1]重复元素还是新元素)

j代表访问的元素下标,for循环内如果当前元素nums[j]不等于前一个元素nums[i-1],代表找到新元素,就把新元素nums[j]放在nums[i]处,此时i++指向下一个元素,j++从该元素位置开始找新元素,重复即可

int removeDuplicates(int* nums, int numsSize) {
    int i=1;//不确定元素下标
    int count=1;//统计唯一元素个数
    for(int j=0;j<numsSize;j++) {
        if(nums[j]!=nums[i-1]) {
            nums[i++]=nums[j];
            count++;
        }
    }
    return count;
}

时间复杂度O(N),空间复杂度是O(1)

那末加大难度

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使得出现次数超过两次的元素只出现两次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

既然不允许额外空间,那末方法一创建数组显然用不了,该怎末做?

思路:上一个题是每一个元素只能出现一次,这个题是每一个元素最多出现2次,那末我们可以仿照方法二来做,只需要改变条件i和j(i j代表意思和上面一样)从第三个元素开始访问,每次nums[j]和nums[i-2]比较,为什么不和nums[i-1]比较,因为题目要求最多出现两次,前面的元素只能是相同的或者不同的

不同 

1 2 2 2 4 4 4   num[2]!=nums[1]为假,会向后找到4并赋值给nums[2],明显不合适,还得加一个统计前面重复元素出现的个数,

相同

例如 1 1  2 2 2 2 3 3 3这种重复元素且至少出现2次,i不好控制

int removeDuplicates(int* nums, int numsSize) {
     if (numsSize <= 2) {//如果数组长度<=2直接返回,此时数组长度为新长度,返回即可
        return numsSize;
    }
    int count=2;
    int i = 2;  // 从第3个元素开始处理
    for (int j = 2; j < numsSize; j++) {
        if (nums[j] != nums[i - 2]) {
            nums[i++] = nums[j];
            count++;
        }
    }
    return count;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值