前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ACM 选手图解 LeetCode 移除元素

ACM 选手图解 LeetCode 移除元素

原创
作者头像
编程文青李狗蛋
发布2022-01-07 10:05:21
3110
发布2022-01-07 10:05:21
举报

大家好呀,我是帅蛋。

最开始在讲数组的时候并没有写实战题,当时想的是数组这么简单,有啥好写的。

直到最近有蛋粉同我讲,才发现是我自己 xue xue 有些飘了。

5864e77a918996c7c586b19151eac29
5864e77a918996c7c586b19151eac29

能写的明明很多嘛!

这让我想到了“知识的诅咒”,当一个人知道了某事,就无法想象这件事在未知者眼中的样子

我引以为戒。


因为数组实在太常用了,我就挑几种类型的题来讲一下,大致是图中读者说的那几个。

以后想起来别的再继续补充。

今天解决移除元素,是快慢指针的经典题目。话不多说,直接开整。

10c1045ba37361eaa7aed40a7b96568
10c1045ba37361eaa7aed40a7b96568

LeetCode 27:移除元素

题意

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

示例

输入:nums = [0,1,2,2,3,0,4,2], val = 2

输出:5, nums = [0,1,4,0,3]

解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。

提示

必须使用 O(1) 空间复杂度并原地修改输入数组。

  • 0 <= len(nums) <= 100
  • 0 <= nums[i] <= 50
  • 0 <= val <= 100

题目解析

水题,题目简单。

这道题相当于数组元素的删除,既然涉及到数组的删除,就不是想当然的删除。

我在文章【ACM 选手带你玩转数组】中讲过:

数组是用连续的一段内存空间,来存储相同数据类型数据的集合。因为这个“连续内存存储”,使得数组在插入或者删除的元素的时候,其它元素也要相应的移动。

这道题数组的数据量很小,最多只到 100 个,所以可以用暴力手法破解。

所谓暴力手法就是最无脑的方式,两层 for 循环,第一层 for 循环从 0 开始遍历数组,第二层 for 循环维护后面的元素向前移动。

比如第一层 for 循环遍历到下标为 2 的位置发现 nums[2] == val,那么第二层循环就将 i+1 ~ n -1 位置上的元素全部向前移动一个位置。

因为是双重 for 循环,此时的时间复杂度为 O(n²)。

虽然也能 AC,但显然作为新时代的三好男人,本帅蛋在这方面追求的肯定不是慢,而是秒男的极致,我要快!

要我快点的话,这就不得不提快慢指针了。

快慢指针,顾名思义,是使用速度不同的指针(可用在链表、数组、序列等上面),来解决一些问题。

快慢指针用 fast 和 slow 两个指针控制,快指针 fast 指向当前要和 val 对比的元素,慢指针 slow 指向将被赋值的位置

  • 遍历数组。
  • 如果 fast 指针指向的元素 nums[fast] != val,则 nums[fast] 是输出数组的元素,将其赋值到 nums[slow] 的位置,slow 和 fast 同时向后移动一位。
  • 如果 nums[fast] == val,证明当前 nums[fast] 是要删除的元素,fast 向后移动一位。
  • fast 遍历完整个数组,结束,slow 的值就是剩余数组的长度。

图解

以 nums = [0,1,2,2,3,0,4,2], val = 2 为例。

首先初始化 fast 和 slow 指针。

cd1c475a49930e45c4bb51feb3a7271
cd1c475a49930e45c4bb51feb3a7271
代码语言:javascript
复制
# 初始化快慢指针
fast = slow = 0

遍历整个数组。

第 1 步,fast = 0,slow = 0,此时 nums[fast] = 0,不等于 val。

此时 nums[slow] = nums[fast](虽然它俩现在本来就是一个),slow 和 fast 向后移动一位。

25876de145355d74e629646b3e36e40
25876de145355d74e629646b3e36e40
代码语言:javascript
复制
# 如果快指针指向的值不等于 val
# fast 指向位置的元素向 slow 指向的位置赋值
if nums[fast] != val:
    nums[slow] = nums[fast]
    slow += 1
    fast += 1

第 2 步,fast = 1,slow = 1,此时 nums[fast] = 1,不等于 val。

此时nums[slow] = nums[fast],slow 和 fast 向后移动一位。

4bc2813c314ec1ff1f15b55247ae5b3
4bc2813c314ec1ff1f15b55247ae5b3

第 3 步,fast = 2,slow = 2,此时 nums[fast] = 2,等于 val。

此时 fast 向后移动一位,slow 不动。

8e3592db04761a2d481077f57ddba9e
8e3592db04761a2d481077f57ddba9e
代码语言:javascript
复制
# 如果快指针指向的值等于 val
# 只 fast 指针移动,不向 slow 指针指向的位置赋值
fast += 1

第 4 步,fast = 3,slow = 2,此时 nums[fast] 依然是 2,等于 val。

所以还是 fast 向后移动一位,slow 不动。

3198d260886f3edf211d0e3bb40ce02
3198d260886f3edf211d0e3bb40ce02

第 5 步,fast = 4,slow = 2,此时 nums[fast] = 3,不等于 val。

此时nums[slow] = nums[fast] = 3,slow 和 fast 向后移动一位。

10b0f075f12d8620ec842aa54f9d7be
10b0f075f12d8620ec842aa54f9d7be

第 6 步,fast = 5,slow = 3,nums[fast] = 0,不等于 val。

此时nums[slow] = nums[fast] = 0,slow 和 fast 向后移动一位。

64b4fa5d11d5d992b60c840e8c80217
64b4fa5d11d5d992b60c840e8c80217

第 7 步,fast = 6,slow = 4,nums[fast] = 4,不等于 val。

此时nums[slow] = nums[fast] = 4,slow 和 fast 向后移动一位。

358bcc605613b94bd6674c8681c4974
358bcc605613b94bd6674c8681c4974

第 8 步,fast = 7,slow = 5,nums[fast] = 2,和 val 相等。

此时 fast 向后移动一位,slow 不变,数组遍历结束。

可以看出,此时从 [0, slow) 为剩下的输出数组,slow 的值为剩下数组的长度。

本道题的解法,使用了一层 for 循环,所以时间复杂度为 O(n)

额外使用了两个指针 fast 和 slow,空间复杂度为 O(1)

代码实现

Python 代码实现

代码语言:javascript
复制
class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
​
        if len(nums) == 0:
            return 0
        # 初始化快慢指针
        fast = slow = 0
​
        while fast < len(nums):
            # 如果快指针指向的值不等于 val
            # fast 指向位置的元素向 slow 指向的位置赋值
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            
            # 如果快指针指向的值等于 val
            # 只 fast 指针移动,不向 slow 指针指向的位置赋值
            fast += 1
​
        return slow

Java 代码实现

代码语言:javascript
复制
class Solution {
    public int removeElement(int[] nums, int val) {
        // 初始化快慢指针
        int fast = 0;
        int slow = 0;
        for (; fast < nums.length; fast++) {
            if (nums[fast] != val) {
                nums[slow] = nums[fast];
                slow++;
            }
        }
        return slow;
​
    }
}

图解移除元素到这就结束辣,数组实战第一篇文章,是不是很有感觉?

这只是一道开胃菜,精彩的题目还在后面呐。

大家记得帮我点赞呀,让我麻溜肝起来!

我是帅蛋,我们下次见!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • LeetCode 27:移除元素
    • 题意
      • 示例
        • 提示
        • 题目解析
        • 图解
        • 代码实现
          • Python 代码实现
            • Java 代码实现
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档