ACM 选手图解 LeetCode 移除元素

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

大家好呀,我是帅蛋。


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


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

image.png能写的明明很多嘛!

image.png

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


我引以为戒。

image.png

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


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


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


image.png

 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,但显然作为新时代的三好男人,本帅蛋在这方面追求的肯定不是慢,而是秒男的极致,我要快!


image.png


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


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


快慢指针用 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 指针。

image.png

# 初始化快慢指针
fast = slow = 0

遍历整个数组。


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


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

image.png

# 如果快指针指向的值不等于 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 向后移动一位。

image.png

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


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


image.png

# 如果快指针指向的值等于 val
# 只 fast 指针移动,不向 slow 指针指向的位置赋值
fast += 1

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


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


image.png

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


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

image.png

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


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

image.png

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


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

image.png

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


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


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


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


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


代码实现


Python 代码实现

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 代码实现

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;
    }
}

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


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


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


我是帅蛋,我们下次见!

相关文章
|
17天前
|
算法
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
【经典LeetCode算法题目专栏分类】【第10期】排序问题、股票问题与TOP K问题:翻转对、买卖股票最佳时机、数组中第K个最大/最小元素
|
25天前
|
算法 搜索推荐 Java
【经典算法】LeetCode 215. 数组中的第K个最大元素(Java/C/Python3实现含注释说明,Medium)
【经典算法】LeetCode 215. 数组中的第K个最大元素(Java/C/Python3实现含注释说明,Medium)
15 3
|
2天前
|
存储 算法 Java
力扣经典150题第四十五题:存在重复元素 II
力扣经典150题第四十五题:存在重复元素 II
5 0
|
11天前
|
索引
leetcode题解:27.移除元素
leetcode题解:27.移除元素
13 0
|
2月前
题目----力扣--移除链表元素
题目----力扣--移除链表元素
24 1
|
2月前
|
存储 算法 索引
【力扣刷题】只出现一次的数字、多数元素、环形链表 II、两数相加
【力扣刷题】只出现一次的数字、多数元素、环形链表 II、两数相加
32 1
|
20天前
|
存储 SQL 算法
LeetCode 83题:删除排序链表中的重复元素【面试】
LeetCode 83题:删除排序链表中的重复元素【面试】
|
20天前
|
存储 SQL 算法
LeetCode 题目 82:删除排序链表中的重复元素 II
LeetCode 题目 82:删除排序链表中的重复元素 II
|
21天前
|
SQL 算法 数据可视化
Leetcode27题:移除元素【27/1000 python】
Leetcode27题:移除元素【27/1000 python】
|
2月前
|
算法 C语言
Leetcode_203.移除链表元素—C语言
Leetcode_203.移除链表元素—C语言