加载中...

在leetcode题库上的移除元素问题(C语言)

今天刚写了一道leetcode上的题,觉得这题的解题思维真的是太棒了。

希望能分享给大家

先看题:

1.给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间原地 修改输入数组,限时间复杂度O(n)

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

 请在下面函数作答:

int removeElement(int* nums, int numsSize, int val)
{
  //语句块
}
 来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/remove-element

 先说一下,这些刷题网大致是分两种的,一种是直接给你一个函数接口,你只需要完成函数接口部分即可;(今天这题是这种)

 另一种是什么都没有,你必须自己写出完整的c代码,也就是从main函数开始写,头文件都要自己引用;


 

首先,我们来分析一下题目的意思:

  1. nums中可能有任意多的数,且不都相同,你需要在nums中找到一个或多个val的值,然后原地删除;
  2. 不能用额外的数组,如果可以使用的话,就有一种比较简单的方法;
  3. 空间复杂度为O(1),时间复杂度O(n)就意味着你不能使用像顺序表删除元素一样,找到val值,就开始删除,删除的过程就是将val值用后一个数往前覆盖,如此下来时间复杂度就会有O(n2)
  4. 原地删除举个例子:在[ 1,2,1,5,4] 中删掉所有的1,你可以删成这样[ 2,5,4,0,0] 或者[ 2,5,4,1,1]我们不需要关系4后面的数是多少,只要数组前面是2,4,5的排列组合就算完成任务;

先介绍一下用额外数组的方法,因为我们可以从这个方法过渡到一种非常神奇的思想:

  图一:自己创建一个数组,并个给定要删除的值,并给出删除方法

 图二:判断元素,不是删除的数,放入新建数组中,依次判断

 

 图三:当判断到有删除数时,不放入新建数组

 图四:判断完后,得到的新建数组

 

总结:这个方法虽然时间复杂度是满足要求O(n),但是空间复杂度不满足,实际上空间复杂度也是O(n)


 

接下来就是非常神奇的思想的讲解,如何即不创建数组又把时间复杂度控制在O(n)内:

假设我们开始有两个不同颜色的标记,nums数组跟val值都跟上面假设一致

 图五:准备两个指针均指向首地址

接下来就是这个思想的过程:

 图六:前三个都是数据不变,到了第四步,指向了被删除的数,黄色不动,黑走

  图七:看图就明白了 图八:看图就明白了

至此,我们就完成了不用额外数组也可以完成删除我们所要选的数据,且都满足了空间复杂度为O(1),时间复杂度O(n)

 

刚开始、现在删除完、之前新建数组删完的对比:

 图九:对比结果

那问题又来了,那该如何解决访问到倒数第二个5就停止访问呢?

其实很简单,记录下每次黑色遇到val值 2就可以了

那就我们直接上代码吧

 1 int removeElement(int* nums, int numsSize, int val)
 2 {
 3     int* p1 = nums;//黑色标记
 4     int* p2 = nums;//黄色标记
 5     int count = 0;//记录下每次黑色遇到val值
 6     while (p1 < nums + numsSize)//黑色指到最后一个元素的下一个元素就停下
 7     {
 8         if (*(p1) != val)//不是val,存入黄色标记处
 9         {
10             *(p2) = *(p1);
11             p2++;//黄色标记向后加一
12         }
13         else//是val记录
14         {
15             count++;
16         }
17         p1++;//黑色标记向后加一
18     }
19     return numsSize -  count;//返回总大小 - val出现的次数
20 }
21 #include <stdio.h>
22 int main()//测试
23 {
24     int arr[] = { 3,1,6,3,5,3,7 };
25     int sz = sizeof(arr) / sizeof(arr[0]);
26     int ret = removeElement(arr, sz, 3);
27     printf("%d ", ret);
28     return 0;
29 }

运行结果:

 

 

跟我们的预期结果一致;

(注:只要前四个是1 , 6 ,  5 , 7 的排列组合就可以了)

总结:这个方法本质来讲就是用双指针来解决问题,如果想了解更多可以到leetcode的官网去看看更多大神的操作;


 

 

更新

2022-03-05

12:05:01

 

 

 

 

 

 

 

 

 

posted @ 2022-03-05 12:07  一名博客  阅读(34)  评论(0编辑  收藏  举报