python实现——LeetCode 27:移除元素

题意:

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

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地** 修改输入数组**。

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

示例:

输入: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) 空间复杂度并原地修改输入数组。O(1)表示所需空间为常量,并且与n无关

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

我的解法:简单粗暴

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        i = len(nums)
        for k, v in enumerate(nums):
            if v == val:
                i -= 1
                a = v
                for j in range(k,len(nums)-1):
                    nums[j] = nums[j+1]
                    nums[len(nums)-1] = a
        return i

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

大神解法

### 方法一:双指针

#### 思路:

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

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

- 遍历数组。
- 如果 fast 指针指向的元素 nums[fast] != val,则 nums[fast] 是输出数组的元素,将其赋值到 nums[slow] 的位置,slow 和 fast 同时向后移动一位。
- 如果 nums[fast] == val,证明当前 nums[fast] 是要删除的元素,fast 向后移动一位。
- fast 遍历完整个数组,结束,slow 的值就是剩余数组的长度。
class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        if len(nums) == 0:
            return 0
        slow = fast = 0
        while fast < len(nums):
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        
        return slow

#### 复杂度分析

时间复杂度:O(n),其中 n为序列的长度。我们只需要遍历该序列至多两次。

空间复杂度:O(1)。我们只需要常数的空间保存若干变量。

方法二:优化双指针

#### 思路:

如果要移除的元素恰好在数组的开头,例如序列 [1,2,3,4,5][1,2,3,4,5],当val 为 1 时,我们需要把每一个元素都左移一位。注意到题目中说:「元素的顺序可以改变」。实际上我们可以直接将最后一个元素 5 移动到序列开头,取代元素 1,得到序列 [5,2,3,4],同样满足题目要求。这个优化在序列中 val 元素的数量较少时非常有效。

实现方面,我们依然使用双指针,两个指针初始时分别位于数组的首尾,向中间移动遍历该序列

#### 算法:

如果左指针left 指向的元素等于 val,此时将右指针right 指向的元素复制到左指针left 的位置,然后右指针 right 左移一位。如果赋值过来的元素恰好也等于val,可以继续把右指针 right 指向的元素的值赋值过来(左指针 left 指向的等于 val 的元素的位置继续被覆盖),直到左指针指向的元素的值不等于val 为止。

当左指针 left 和右指针 right 重合的时候,左右指针遍历完数组中所有的元素。

这样的方法两个指针在最坏的情况下合起来只遍历了数组一次。与方法一不同的是,方法二避免了需要保留的元素的重复赋值操作。

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        left = 0
        right = len(nums)-1
        while left <= right:
            if nums[left] == val:
                nums[left] = nums[right]
                right -= 1
            else:
                left += 1

        
        return left
#### 根据思路和算法写代码出现的问题!!:

while left != right:如果用!=或<,会遗漏一个元素(left==right时)!严谨一点,可以再优化为以下代码,**避免**当指针left遍历完最后一个元素后,指针left在指针right右边:

在这里插入图片描述

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        left = 0
        right = len(nums)
        while left < right:
            if nums[left] == val:
                nums[left] = nums[right-1]
                right -= 1
            else:
                left += 1

        
        return left
#### 复杂度分析

- 时间复杂度:O(n),其中 nn 为序列的长度。我们只需要遍历该序列至多一次。
- 空间复杂度:O(1)。我们只需要常数的空间保存若干变量。

引用:
1.ACM 选手图解 LeetCode 移除元素:https://mp.weixin.qq.com/s?__biz=MzI0NjAxMDU5NA==&mid=2475922234&idx=1&sn=5f0a3fce40927c80ff5608da90b6fcd0&chksm=ff22f4b7c8557da10186decdfd4b1f57277b44e1f452388be2ef407bd5e91f8b2e24c624fceb&token=1145569493&lang=zh_CN#rd

2.:力扣(LeetCode)https://leetcode.cn/problems/remove-element/solution/yi-chu-yuan-su-by-leetcode-solution-svxi/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KMP算法是一种字符串匹配算法,用于在一个文本串S内查找一个模式串P的出现位置。它的时间复杂度为O(n+m),其中n为文本串的长度,m为模式串的长度。 KMP算法的核心思想是利用已知信息来避免不必要的字符比较。具体来说,它维护一个next数组,其中next[i]表示当第i个字符匹配失败时,下一次匹配应该从模式串的第next[i]个字符开始。 我们可以通过一个简单的例子来理解KMP算法的思想。假设文本串为S="ababababca",模式串为P="abababca",我们想要在S中查找P的出现位置。 首先,我们可以将P的每个前缀和后缀进行比较,得到next数组: | i | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | | --- | - | - | - | - | - | - | - | - | | P | a | b | a | b | a | b | c | a | | next| 0 | 0 | 1 | 2 | 3 | 4 | 0 | 1 | 接下来,我们从S的第一个字符开始匹配P。当S的第七个字符和P的第七个字符匹配失败时,我们可以利用next[6]=4,将P向右移动4个字符,使得P的第五个字符与S的第七个字符对齐。此时,我们可以发现P的前五个字符和S的前五个字符已经匹配成功了。因此,我们可以继续从S的第六个字符开始匹配P。 当S的第十个字符和P的第八个字符匹配失败时,我们可以利用next[7]=1,将P向右移动一个字符,使得P的第一个字符和S的第十个字符对齐。此时,我们可以发现P的前一个字符和S的第十个字符已经匹配成功了。因此,我们可以继续从S的第十一个字符开始匹配P。 最终,我们可以发现P出现在S的第二个位置。 下面是KMP算法的C++代码实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值