力扣练习——移除元素(python)

这个题解决了两个疑问:
1.for循环中不能用原地法将列表中的特定元素删除干净,但while循环可以(解释)。
2.双指针的思想很巧妙

问题描述

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

不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

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

示例 1:
给定 nums = [3,2,2,3], val = 3,
函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。


示例 2:
给定 nums = [0,1,2,2,3,0,4,2], val = 2,
函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。
注意这五个元素可为任意顺序。


来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/remove-element

思路与提示

思路

如果将列表中值为val的元素直接pop或者remove出,很容易就可以实现。但是操作的时候发现用for 循环无法将列表中的特定元素删除干净。

官方提示

1.Try two pointers.
2.Did you use the property of “the order of elements can be changed”?
3.What happens when the elements to remove are rare?

代码

while 循环

class Solution(object):
    def removeElement(self, nums, val):
        """
        :type nums: List[int]
        :type val: int
        :rtype: int
        """
        while val in nums:
            nums.remove(val)
        return len(nums)

双指针

1.代码:

class Solution:
    def removeElement(self, nums: List[int], val: int) -> int:
        if not nums:return 0
        slow = 0   
        n = len(nums)
        fast = n - 1
        while slow < fast:
            while slow < fast and nums[slow] != val:
                slow += 1
            while slow < fast and nums[fast] == val:
                fast -= 1
            nums[slow],nums[fast] = nums[fast],nums[slow]
            slow += 1
            fast -= 1
        res = 0
        #print(nums,slow,fast)
        #return fast + 1
        for i in range(n):
            if nums[i] == val:
                return res
            res += 1

#作者:powcai
#链接:https://leetcode-cn.com/problems/remove-element/solution/yi-chu-yuan-su-by-powcai/
#来源:力扣(LeetCode)
#著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

2.解释:

以题中的 nums = [3,2,2,3], val = 3 为例。
开始时 i 和 j 都指向下标 0 位置:
在这里插入图片描述
此时 j 指向的元素为 val,所以把 j 右移动 1 位:
在这里插入图片描述
此时,开拓者 j 找到了一个非 val 元素,那么就赋值给 i 吧:
当然,我们为了让用户更加便捷,我们增加了图片拖拽功能。
赋值以后,我们得到了一个新的序列 [2, 2, 2, 3],我们可以得知:
– i 指向的元素一定不是 val,因为它是从 j 指向的元素赋值得来的,j 指向非 val 元素才会进行赋值
– j 指向的元素一定不是非 val???
这样一来,i 和 j 都完成了本轮使命,继续前进!
因此每次交换以后,我们都同步增长双指针,令 i = i + 1,j = j + 1:
在这里插入图片描述
此时 j 又指向了一个非 val 元素,继续赋值:
在这里插入图片描述
因为本次 i 与 j 指向元素相同,所以赋值后序列没有改变。赋值操作后,我们继续同步增长双指针:
在这里插入图片描述
此时 j 指向了一个 val 元素,无法进行赋值操作,继续增长 j,令 j = j + 1:
在这里插入图片描述
此时我们发现 j 超出数组范围了,循环结束。[2, 2, 2, 3] 即为我们最终所求结果,而红色部分即为新数组长度,长度为 len(nums) - (j - i)。


作者:jalan
链接:https://leetcode-cn.com/problems/remove-element/solution/tu-jie-shuang-zhi-zhen-leetcode-27-yi-chu-yuan-su-/
来源:力扣(LeetCode)

总结

1.两种方法的时间复杂度应该都是O(n)。但在while循环中,数组增删都比较耗资源(可以了解一下pop这个方法内部的实现又有多少复杂度)。
2.双指针似乎有更优雅的写法

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值