Python 双指针系列(Leetcode1 两数之和 Leetcode15. 三数之和 Leetcode 31. 下一个排列)

Leetcode1 两数之和

Leetcode1 两数之和,这道题逻辑应该很简单,我认为是最简单的简单题了,没什么好说的
在这里插入图片描述

class Solution:
    def twoSum(self, nums: List[int], target: int) -> List[int]:
        result = []
        n = len(nums)
        for i in range(n):
            for j in range(i+1,n):
                if nums[i]+ nums[j] == target:
                  result.append(i)
                  result.append(j)
        return result

Leetcode15 三数之和

Leetcode15 三数之和,其实也是利用双指针,不多说,上代码
在这里插入图片描述
算法流程:

    1、特判,对于数组长度n,如果数组为null或者数组长度小于3,返回[ ]
    2、对重复数组:跳过,避免出现重复解
    3、令左指针L= i+1, 右指针R=n-1,当L<R时,执行循环:
    		当nums[i] +nums[L]+nums[R] == 0,执行循环,判断左界和右界是否和下一位置重复,去除重复解,并同时将L,R移到下一位置,寻找新的解
    	    若和大于0,说明nums[R]太大,R左移
    	    若和小于0,说明nums[L]太小,L右移
class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        # 1、特判,对于数组长度n,如果数组为null或者数组长度小于3,返回[]
        # 2、对重复数组:跳过,避免出现重复解
        # 令左指针L= i+1, 右指针R=n-1,当L<R时,执行循环:
        #   当nums[i] +nums[L]+nums[R] == 0,执行循环,判断左界和右界是否和下一位置重复,去除重复解,并同时将L,R移到下一位置,寻找新的解
        #   若和大于0,说明nums[R]太大,R左移
        #   若和小于0,说明nums[L]太小,L右移
        # 复杂度分析:时间复杂的 O(n^2),数组排序O(NlogN),遍历数组O(n),双指针遍历O(n),总体O(NlogN)+O(n^2)
        n = len(nums)
        res = []
        if not nums or n<3:
            return []
        nums.sort() # 升序
        for i in range(n):
            if nums[i]>0:
                return res
            if i>0 and nums[i] == nums[i-1]: # 当i>0,即从i=1开始就需要判断,如果相邻的两个数相同,则会出现重复解
                continue
            L = i+1
            R = n-1
            while L<R:
                if nums[i]+nums[L]+nums[R] == 0:
                    res.append([nums[i],nums[L],nums[R]])
                    while L<R and nums[L] == nums[L+1]: # 避免第二位出现重复解
                        L = L+1
                    while L<R and nums[R] == nums[R-1]: # 避免第三位出现重复解
                        R = R-1
                    L = L+1
                    R = R-1
                elif nums[i]+nums[L]+nums[R] >0:
                    R = R-1
                else:
                    L = L+1
        return res   

Leetcode 31. 下一个排列

在这里插入图片描述
必须原地修改,只允许使用额外常数空间,即不能是由栈和队列或者构建列表之类的

这里我举一个例子:例如, nums=[1,3,3,9,6,5,4],那么它的下一排序是什么呢?
读懂题的小伙伴一定知道下一个排列是[1,3,4,3,5,6,9] 其实这个就是字典序的排列,不太懂的可以查一下

这里讲一个方法,就是从后向前找一个对相邻元素对,这个元素对应该满足什么呢?应该满足升序,即设两个指针 i, j (i+1=j), 且如果满足nums[i]<nums[j],那么一定满足从j元素到nums的最后一个元素是降序的,如nums= [1,3,3,9,6,5,4]中第一个符合条件的元素对索引是(2,3)对应元素是3,9。之后我们在[j.end)中找到第一个比nums[i]大的元素这里是4,将nums[i]与4互换,此时nums=[1,3,4,9,6,5,3],[j,end)天然满足降序排列,我们此时将nums[j]到nums[end]升序即可。最后得到结果nums=[1,3,4,3,5,6,9]

算法流程:
标准的“下一个排列”算法可以描述为:
1、从后向前 查找第一个相邻升序的元素对(i,j),满足A[i]<A[j]。此时,[j,end)天然降序
2、在[j,end)从后向前查找第一个满足A[i]<A[k]的k。A[i]、A[k]分别是局部最小数相较于局部最小数的较大数
3、将A[i]与A[k]交换
4、可以断定此时[j,end)必然是降序, 逆置[j,end),使其升序
5、如果在步骤1中找不到符合的相邻元素对,说明当前[begin,end)为一个降序顺序,则直接跳到步骤

可视化
以求 12385764 的下一个排列为例:
在这里插入图片描述
首先从后向前查找第一个相邻升序的元素对 (i,j)。这里 i=4,j=5,对应的值为 5,7:
在这里插入图片描述
然后在 [j,end) 从后向前查找第一个大于 A[i] 的值 A[k]。这里 A[i] 是 5,故 A[k] 是 6:
在这里插入图片描述
将 A[i] 与 A[k] 交换。这里交换 5、6:
在这里插入图片描述
这时 [j,end) 必然是降序,逆置 [j,end),使其升序。这里逆置 [7,5,4]:
在这里插入图片描述
因此,12385764 的下一个排列就是 12386457。
最后再可视化地对比一下这两个相邻的排列(橙色是蓝色的下一个排列):
在这里插入图片描述

class Solution:
    def nextPermutation(self, nums: List[int]) -> None:
        """
        Do not return anything, modify nums in-place instead.
        """
        i,j,k = len(nums)-2,len(nums)-1,len(nums)-1
        # find A[i] A[j]
        while i>=0 and nums[i]>nums[j]:
        	i-=1
        	j-=1
        if i>=0: # 不是最后一个排列
        	# find:A[i]<A[j]
        	while nums[i]>= nums[k]:
        		k-=1
        	# swap A[i],A[k]:
        	nums[i], nums[k] = nums[k], nums[i]
        # reberse A[j:end]
        end = len(nums)-1
        while j<end:
        	nums[j], nums[end] = nums[end], nums[j]
        	j+=1
        	end-=1 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值