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右边:

python实现——LeetCode 27:移除元素_第1张图片

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/

你可能感兴趣的:(leetcode,leetcode,算法,职场和发展)