【算法总结】双指针算法总结

双指针:

(1)27. 移除元素
题目描述:
给你一个数组 nums 和一个值 val,你需要原地移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
代码:

class Solution(object):
    def removeElement(self, nums, val):
        fast = 0
        slow = 0
        while fast < len(nums):
            if nums[fast] != val:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow
  • 时间复杂度O(n)
  • 空间复杂度O(1)

解释:
题目中重要的限制信息:不要使用额外的数组空间。暴力解法就需要双循环,第一次for旬循环找nums中数值不等于val的元素,第二次循环更新nums中的数值,时间复杂度是O(n^2),空间杂度O(1)。
考虑使用双指针。第一个指针(fast)不断寻找nums中数值不等于val的元素,第二个指针(slow)更新nums数组,当第一个指针到顶了以后,则nums前slow项已经全部更新完成,时间复杂度是O(n),空间复杂度O(1)。
步骤:
第一步:设置快慢指针
第二步:当fast指针到达列表最后一项时候停止更新fast指针
第三步:当fast指针所指元素不等于val时更新slow指针所指元素
第四步:当fast指针超过i列表最后一项时候返回slow的值,此时前slow项元素已经全部完成更新

(2)26. 删除有序数组中的重复项
题目描述:
给你一个有序数组 nums ,请你原地删除重复出现的元素,使每个元素只出现一次,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
代码:

class Solution(object):
    def removeDuplicates(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if not nums:
            return 0
        slow = 0
        fast = 1
        while fast < len(nums):
            if nums[fast]!= nums[slow]:
                slow += 1
                nums[slow] = nums[fast]
            fast += 1
        return slow+1

  • 时间复杂度O(n)
  • 空间复杂度O(1)

解释:
典型的双指针问题,有几个点需要注意:第一点是考虑数组长度为0的特殊情况,当长度为0时,数组不存在,也就没有办法通过后续的判断条件删除数组。第二点是当fast指针和slow指针所指的元素不同时,先将slow右移,再完成赋值。

(3)283. 移动零
题目描述:
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
代码:

class Solution(object):
    def moveZeroes(self, nums):
        """
        :type nums: List[int]
        :rtype: None Do not return anything, modify nums in-place instead.
        """
        slow =  0
        fast = 0 
        while fast < len(nums):
            if nums[fast] != 0:
                nums[slow], nums[fast] = nums[fast], nums[slow] #交换
                left += 1
            fast += 1
       return nums
  • 时间复杂度O(n)
  • 空间复杂度O(1)

解释:
典型双指针,需要注意的是交换的操作,nums[slow], nums[fast] = nums[fast], nums[slow],快指针指到非0元素的时候就和慢指针交换一下,这样就把所有的非0元素交换到了nums[ : slow+1],则剩余的0元素就集中在nums[slow+1 : -1]

(4)977. 有序数组的平方
题目描述:
给你一个按非递减顺序排序的整数数组 nums,返回每个数字的平方组成的新数组,要求也按非递减顺序排序。
代码:

class Solution(object):
    def sortedSquares(self, nums):
        #两边大中间小,那么谁大把谁放进去就好了
        n = len(nums)
        i = 0
        j = n-1
        ins = n-1
        ans = [0]*n
        while j >= i:
            if nums[j]*nums[j] >= nums[i]*nums[i]:
                ans[ins] = nums[j]*nums[j]
                j -= 1
                ins -= 1
            else:
                ans[ins] = nums[i]*nums[i]
                i += 1
                ins -= 1
        return ans
  • 时间复杂度O(n)
  • 空间复杂度O(1)

解释:
因为题目说明了非递减,那么数组两边元素的平方整体是比中间元素的平方大的,那么只需要双指针比较两端的平方大小,不断的压缩空间就可以啦。

总结

双指针的本质还是解决两个问题 1. 怎么建立快慢指针2. 快慢指针更新的条件,遇到双指针的题,从这两个问题入手,思路就会比较清晰。

写在最后,之前断断续续的刷过一些题,因为没有归纳整理,过一段时间后可能就忘记了,所以现在准备按照Carl大佬写的代码随想录重新系统的刷一遍leetcode,最后通过博客进行总结归纳,时常看看,如果有新的感悟也方便更新。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值