C语言数据结构-删除数组中的重复项

1.题目描述:

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

       由于在某些语言中不能改变数组的长度,所以必须将结果放在数组nums的第一部分。更规范地说,如果在删除重复项之后有 k 个元素,那么 nums 的前 k 个元素应该保存最终结果。将最终结果插入 nums 的前 k 个位置后返回 k 。不要使用额外的空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/remove-duplicates-from-sorted-array


2.编程思路:

        对于数据结构题目的编程思路,我建议大家直接画图,画图能够帮助我们更全面地思考问题。首先明确目标是删除有序(升序)数列的重复项。如果我们不考虑时间和空间复杂度,那么最先想到的就是方法1——遍历删除。也就是定义两个序号Start从0开始、End从1开始,如果两者指向的元素相等就说明有重复数据出现,然后将End和以后的数据都向前挪动,直到End指向数组的最后一个元素,如图1所示。

图1

       这种方法能够完成功能,但是并不能满足要求,因为时间复杂度为O(n^2)。所谓时间复杂度就是执行简单代码的次数,上述方法在最坏的情况下(全部都是一样的数据)需要移动(也就是值覆盖)n-1、n-2、...、2、1,利用等差数列求和可以求出一共需要有n*(n-1)/2次赋值操作,所以时间复杂度就是O(n^2)。没有开辟新的空间,所以空间复杂度是O(1)。

       方法2:我们重新开辟一个数组,也用两个序号进行操作,Src遍历指向原数组,Dst遍历指向新开辟的数组。不同的是,我们不移动后面的所有值,而是只要Src和Dst所指向的数据不同就将Src所指向的数据赋给Dst所指向的空间,这里的细节一定要注意,谁走在前面,谁赋值给谁。如图2所示。

 图2

      这种方法也能实现功能,但是空间复杂度是O(n),不能满足要求。

        方法3:我们可以从上面两种简单粗暴的方法中吸取优点,就是让两个序号去遍历,最后将满足条件的的值赋给自己,也就是数组内的值覆盖。如图3所示,我们让Start和End两个序号去遍历原数组,如果两个不等就将Start所指向的数据赋给Dst所指向的空间,这也是所谓的三指针,但是成作序号更好理解。这里有一个细节就是会有End越界的时候,这时候就有最后两个数是相等还是不等两种情况,但是不管是哪种情况都应该把Start所指向的数据赋给Dst所指向的空间。(这点大家画图好好想一下,虽然简单,但是是细节!)

 图3

        时间复杂度:这个相当于执行n次条件赋值操作,所以就是O(n),空间复杂度为O(1)。

3.代码

int removeDuplicates(int* nums, int numsSize){
    // 处理空数组整个特殊情况
    if(numsSize == 0)
    {
        return 0;   
    }
    // 定义三个序号
    int Start = 0;
    int End = 1;
    int Dst = 0;
    while(End<numsSize)
    {
        // Start End 所指向的数据不等时值覆盖
        if(nums[Start]!=nums[End])
         {
            nums[Dst]=nums[Start];
            End++;
            Start++;
            Dst++;
         }
        // 相等时继续遍历不赋值
        else
        {
            Start++;
            End++; 
        }
    }
    // 考虑End已经越界的时候
    nums[Dst] = nums[Start];
    Dst++;
    return Dst;
}

4.总结

        对于C语言的数据结构,最重要的就是画图(这能够帮助理清逻辑)、分析复杂度、敲代码!


  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三昧书生731

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值