Python算法——双指针

双指针(Two Pointers):指的是在遍历元素的过程中,不是使用单个指针进行访问,而是使用两个指针进行访问,从而达到相应的目的。

双指针分为「对撞指针」、「快慢指针」、「分离双指针」。

    对撞指针:两个指针方向相反。适合解决查找有序数组中满足某些约束条件的一组元素问题、字符串反转问题。

    快慢指针:两个指针方向相同。适合解决数组中的移动、删除元素问题,或者链表中的判断是否有环、长度问题。

    分离双指针:两个指针分别属于不同的数组 / 链表。适合解决有序数组合并,求交集、并集问题。

一,对撞指针

1.盛最多水的容器

输入:[1,8,6,2,5,4,8,3,7]
输出:49
解释:图中垂直线代表输入数组
[1,8,6,2,5,4,8,3,7]。在此情况下,容器能够容纳水(表示为蓝色部分)的最大值为 49。

class Solution:
    def maxArea(self, height: List[int]) -> int:
        result = 0
        left = 0
        right = len(height) - 1
        while left < right:
            # 求解矩形的面积
            l = right - left
            h = min(height[left], height[right])
            area = l*h
            # 需要不断维持更新最大值
            result = max(result, area)
            # 应该使得 较低直线的高度尽可能的高
            # 当left指向的直线高度较低,向右移动
            if height[left] < height[right]:
                left += 1
            # 当right指向的直线高度较低,向左移动
            else:
                right -= 1
        return result
2.反转字符串

输入:s = [“h”,“e”,“l”,“l”,“o”]
输出:[“o”,“l”,“l”,“e”,“h”]

class Solution:
    def reverseString(self, s: List[str]) -> None:
        """
        Do not return anything, modify s in-place instead.
        """
        left = 0
        right = len(s) - 1
        while left < right:
            s[left], s[right] = s[right], s[left]
            left += 1
            right -= 1
        return s

二,快慢指针

删除有序数组中的重复项
输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素
class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        # 定义两个指针
        slow = 0
        fast = 1
        # 可以视作把非重复元素放在数组左边
        while fast < len(nums):
            if nums[slow] != nums[fast]:
                slow += 1
                nums[slow] = nums[fast]
            fast += 1
        return slow + 1

三,分离指针

两个数组的交集

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2]

class Solution:
    def intersection(self, nums1: List[int], nums2: List[int]) -> List[int]:
        # 分离双指针一般用于处理有序数组合并,求交集、并集问题
        # 1 先将两个数组排序
        nums1.sort()
        nums2.sort()
        # 使用双指针求交集
        point1 = 0
        point2 = 0
        result = []
        while point1 < len(nums1) and point2 < len(nums2):
            # 元素同时出现在两个数组
            if nums1[point1] == nums2[point2]:
                # 保证数组没有重复元素
                if nums1[point1] not in result:
                    result.append(nums1[point1])
                # 齐头并进
                point1 += 1
                point2 += 1
            # point1落后于point2,需要追赶
            elif nums1[point1] < nums2[point2]:
                point1 += 1
            # point2落后于point1,需要追赶   
            else:
                point2 += 1
        return result

其他类型

合并两个有序数组

输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]

        # 定义两个指针,分别指向数组的尾部
        p1 = m-1
        p2 = n-1
        p = m + n - 1
        while p1 >= 0 and p2 >= 0:
            if nums1[p1] <= nums2[p2]:
                nums1[p] = nums2[p2]
                p2 -= 1
            else:
                nums1[p] = nums1[p1]
                p1 -= 1
            p -= 1
        # 最后把nums2中的剩余元素赋值到nums1中
        nums1[:p2+1] = nums2[:p2+1]

删除有序数组中的重复项 II

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 最多出现两次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

输入:nums = [1,1,1,2,2,3]
输出:5, nums = [1,1,2,2,3]

class Solution:
    def removeDuplicates(self, nums: List[int]) -> int:
        slow = 2
        fast = 2
        # 因为有序,所以当 nums[slow-2] = nums[slow]时,
        # 必有nums[slow] = nums[slow-1] = nums[slow-2]
        # 不相等时进行添加
        while fast < len(nums):
            if nums[slow-2] != nums[fast]:
                nums[slow] = nums[fast]
                slow += 1
            fast += 1
        return slow

三位数之和

给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。

输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        result = []                  # 结果输出
        n = len(nums)
        # 先将数组递增排列
        nums.sort()
        # 定义双指针 a, left, right
        for i in range(n):
            if i > 0 and nums[i] == nums[i-1]:
                continue
            left = i+1
            right = n-1
            # 双指针寻找区间
            while left < right:
                # 答案中不可以包含重复的三元组,对于重复的元素直接跳过
                while left < right and left > i+1 and nums[left] == nums[left-1]:
                    left += 1
                while left < right and right < n-1 and nums[right] == nums[right+1]:
                    right -= 1
                # 满足条件的三元组
                if left < right and nums[i] + nums[left] + nums[right] == 0:
                    result.append([nums[i], nums[left], nums[right]])
                    left += 1
                    right -= 1
                elif nums[i] + nums[left] + nums[right] > 0:
                    right -= 1
                else:
                    left += 1
        return result

以上问题都来源于力扣:

力扣>
参考来源:https://algo.itcharge.cn/

  • 17
    点赞
  • 101
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值