删除有序数组的重复项

128 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第20天,点击查看活动详情


大家好,我是芒果,一名非科班的在校大学生。对C/C++、数据结构、Linux及MySql、算法等领域感兴趣,喜欢将所学知识写成博客记录下来。 希望该文章对你有所帮助!如果有错误请大佬们指正!共同学习交流

作者简介:

题目

链接:leetcode-cn.com/problems/re…


image-20220209215336712

  • 给定的输入数组是已经排好序的
  • 需要在原地删除重复的元素,也就是说我们不可以在重新定义数组来存放结果,需要对原数组进行修改
  • 返回的是修改之后数组的长度,而不是数组本身
  • 不需要考虑数组中超出新长度后面的元素,也就是说,我们可以将原数组的前一部分更新为我们想要的结果,然后返回这部分的长度即可,不需要考虑着部分之后的元素是否也符合要求。
  • 1.如果numsSize为0,说明数组没有元素,返回0

方法1:覆盖大法(不符合题目要求)

  • 因为数组是有序的,所以可以数组元素前后比较,如果前后元素相等,就把后面的元素往前覆盖掉,然后标志数组元素的变量 numsSize--

  • 覆盖之后,i还要从原来删除的位置再次判断覆盖后的元素和后面的元素是否一样,,不可以直接i++ ,因为如果覆盖后元素也是重复的元素,直接i++的话,就会出现错误

    • image-20220209215351318
  • 综上,如果是要覆盖的话,i还要从原位置继续判断和后面的元素是否一样,防止出现多个重复元素一起出现


图解

image-20220209215408857


image-20220209215424271

int removeDuplicates(int* nums, int numsSize)
{
    if (numsSize == 0)
    {
        return 0;
    }
    int i = 0;
    for (i = 0; i < numsSize -1; i++)  //i的最大范围是:numsSize - 2  它的后一个元素就是最后一个元素 
        //如果i < numsSize 则会越界 i的max为:numsSize - 1 后一个元素超出数组范围
    {
        //如果前一个元素和后一个元素一样,就删掉一个
        if (nums[i] == nums[i + 1])
        {
            int j = i ;
            //后面的元素往前覆盖
            for (; j <numsSize -1; j++)
            {
                nums[j] = nums[j+1];
            }
            //删除了一个元素:
            numsSize--;
            //还要从被覆盖位置继续比较
            i--;//和for循环的i++抵消
        }
    }
    return numsSize;
}

方法2:双指针

方法:

数组是有序的!!! 本质就是j找到和i不相同的元素,然后放到i的下一个位置,i++, 然后不断重复这个过程,直到把数组遍历完

  • 定义两个变量i和j,i从0开始,j从1开始,j在i的后面找和i指向不相同的元素,
  • 当i和j指向的元素一样时:j++,i不动
  • 当i和j指向的元素不一样时:(即:跳过了重复的元素):把此时j指向的元素放到i+1的位置,然后i++ (或者先:i++ 然后放到此时i的位置) j不动
  • 然后开始第二轮寻找与此时i指向不同的元素 j的范围为:j<numsSize 其中numsSize是元素个数
  • 注意:最后返回的是i+1的值 ,因为i的下标从0开始,而元素个数从1开始。

图解

int removeDuplicates(int* nums, int numsSize)
{
    if(numsSize == 0)
    {
        return 0;
    }
    int i = 0;
    int j = 1;
    while(j<numsSize)
    {
         if(nums[i] == nums[j])
        {
            j++;
        }
        else
        {
            nums[i+1]=nums[j];
            i++;
            //这里加上j++也可也
        }
    }
    return i + 1;
}

方法3:三指针

*方法:*定义三个变量

  • 变量作用

    i:用来标志要查找的数字

    j:用于遍历数组,j在i后面,找到和i不同的元素

    dest:用于存放不重复元素

  • 如果j和i指向的值相同:j++

  • 如果j和i指向的值不相同:就把此时i位置的值放到dest位置,然后dest++,然后把i指向j位置,然后j++,j在i后面,继续找和此时i位置不同的值,然后再放到dest位置...以此重复

  • 循环条件:j < numsSize

  • 注意:最后跳出循环时,还要把此时i位置的值再赋给dest,dest再++,dest标志的就是不重复的成员个数


图解

image-20220209215438469


image-20220209215452595


image-20220209215509356


image-20220209215515432

int removeDuplicates(int* nums, int numsSize)
{
    if(numsSize == 0)
    {
        return 0;
    }
    int i = 0;
    int j = i+1;
    int dest = 0;
    while(j<numsSize)
    {
        if(nums[i] == nums[j])
        {
            j++;
        }
        else
        {
            nums[dest] = nums[i];
            dest++;
            i = j;
            j++;
        }
    }
    nums[dest] = nums[i];
    dest++;
    return dest;
}

\