L1.【LeetCode笔记】删除有序数组中重复项

1.题目

https://leetcode.cn/problems/remove-duplicates-from-sorted-array/description/

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

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

  • 更改数组 nums ,使 nums 的前 k 个元素包含唯一元素,并按照它们最初在 nums 中出现的顺序排列。nums 的其余元素与 nums 的大小不重要。
  • 返回 k 。

判题标准:

系统会用下面的代码来测试你的题解:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

如果所有断言都通过,那么您的题解将被 通过

示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 不需要考虑数组中超出新长度后面的元素。

示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

提示:

扫描二维码关注公众号,回复: 17421758 查看本文章
  • 1 <= nums.length <= 3 * 104
  • -104 <= nums[i] <= 104
  • nums 已按 非严格递增 排列

 2.自解

测试用例

case 1 [1,1,1,2]
case 2 [1,1,2]
case 3 [0,0,1,1,1,2,2,3,3,4]

显然考察顺序表的中间元素的删除算法

(具体内容见85.【C语言】数据结构之顺序表的中间插入和删除及遍历查找)

第一次

照抄第85篇的删除函数

void Erase(int** arr,int pos,int* numsSize)
{
    int begin=pos+1;
    	while (begin < (*numsSize))
	{
		(*arr)[begin - 1] = (*arr)[begin];
		begin++;
	}
	(*numsSize)--;

}

int removeDuplicates(int* nums, int numsSize) 
{
    int i=0;
      if (nums[i]==nums[i+1])
      {
        Erase(&nums,i,&numsSize);
      }
    return numsSize;
}

发现case 1不通过 case 2通过 case3不通过

应该调用循环

第二次

int removeDuplicates(int* nums, int numsSize) 
{
    int i=0;
    while (i<numsSize-1)
    {
      while (nums[i]==nums[i+1])
      {
        Erase(&nums,i,&numsSize);
      }
      i++;
    }
    return numsSize;
}

case1,2,3都通过,提交后发现卡在了[1,1]上

检查原因后发现:因为i是传值调用,当Erase函数返回后,形参pos被销毁,因此要改成传址调用

第三次

void Erase(int** arr, int* pos, int* numsSize)
{
    int begin = *pos + 1;
    while (begin < (*numsSize))
    {
        (*arr)[begin - 1] = (*arr)[begin];
        begin++;
    }
    (*numsSize)--;
}

int removeDuplicates(int* nums, int numsSize)
{
    int i = 0;
    while (i < numsSize - 1)
    {
        while (nums[i] == nums[i + 1])
        {
            Erase(&nums, &i, &numsSize);
        }
        i++;
    }
    return numsSize;
}

但改成传址调用后仍然[1,1]通过不了,进VS2022调试以后,发现是main函数的while循环出现了问题

第四次

void Erase(int* arr, int pos, int* numsSize)
{
    for (int i = pos; i < *(numsSize)-1; i++)
    {
        arr[i] = arr[i + 1];
    }
    (*numsSize)--;
}

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

提交后通过

关键的地方在于:删除重复的元素后,i才+1;(对应else {i++;})

3.力扣官方题解

使用指针算法

int removeDuplicates(int* nums, int numsSize) 
{
    if (numsSize == 0) 
    {
        return 0;
    }
    int fast = 1, slow = 1;
    while (fast < numsSize) 
    {
        if (nums[fast] != nums[fast - 1]) 
        {
            nums[slow] = nums[fast];
            ++slow;
        }
        ++fast;
    }
    return slow;
}

其中[fast]为快指针,[slow]为慢指针

本题双指针算法的过程:

1.当nums[fast] == nums[fast-1]时,只有fast++

2.当nums[fast] != nums[fast-1]时,slow++;

猜你喜欢

转载自blog.csdn.net/2401_85828611/article/details/143192036