ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python刷题--N数之和问题(双指针+剪枝)

2022-02-03 23:35:19  阅读:242  来源: 互联网

标签:剪枝 target nums python j1 -- second first 指针


1.两数之和(双指针)

这题前面已经做过,当时是用哈希表做的,时间复杂度为N

但如果换一种思路,用今天学的双指针来做,虽然在时间复杂度上不降反增(因为排序的复杂度为NlogN)但理解起来十分简单清晰。(注:对于三数四数N数之和问题来说,双指针算法相当于将最内部的两层循环优化成一层。)

思路:即先排序,得到一个有序的列表,一个指针指向列表开头,一个指向末尾,对于每一个状态而言,如果大于目标值则让右指针左移,小于目标值则让左指针右移。该方法适用于求无重复的解。

个人题解:

# 注释1
class Solution:
    def twoSum(self, nums: List[int], target: int):
        res = []
        i, j = 0, len(nums)-1
        nums.sort()
        for i in range(len(nums)):
            if i > 0 and nums[i-1] == nums[i]:
                continue
            while i < j and nums[i] + nums[j] > target:
                j -= 1
            if i == j:  # 注释2,3
                break
            if nums[i] + nums[j] == target:
                res.append([nums[i], nums[j]])
        return res

注释1:# 注意这不是题目:两数之和的解,这代码的条件是跟后面的三数之和四数之和相同时才能成立(必须要求只返回目标值而不是返回索引)

注释2:# 能导致i=j的只有两种情况。一:由内层循环得到,那么当前状态的前一个状态nums[i]+nums[j] 是大于target的,此时期待减少两个数的和,但是控制减小的指针j已经无法向左移,所以循环结束二:由外层循环得到,那么当前状态的前一个状态nums[i]+nums[j]是小于target的,此时期待增大两个数的和,但是控制增大的指针i已经无法向右移,循环结束

注释3:在上述情况发生时(期待增大的两个数之和,但是控制增大的指针i无法向右移)。那么可不可以让j往右移动(回头)呢?

答:是不行的。看上去j向右移动,和这个状态的i是一组全新的i,j组合,是没有遍历过的,那为什么不能这样呢?

我们来假设这样的情况成立。。假设在移动之前i和j的位置分别为i0和j0那么j0向右移动后移到某个j1的位置,此时nums[i0]+nums[j1]的值是大于等于0(或者目标值的),假设i在最开始的位置是i1,那么当j第一次运动到j1的位置时,i在i1的位置,这个时候的nums[i1]+nums[j1]是小于nums[i0]+nums[j1]的,而j1运动到j0是为了使整体值减小,那么第一次的nums[i1]+nums[j1]一定就是大于0,所以对比两个状态,i1和j1这个状态下已经大于0,那么就不会再让i1增大得到i0,所以与我们一开始设定好的值大就减小,值小就增大的思想不符,假设不成立。

2.三数之和

题目:https://leetcode-cn.com/problems/3sum/

官方题解:

class Solution:
    def threeSum(self, nums: List[int]) -> List[List[int]]:
        n = len(nums)
        nums.sort()
        ans = list()
        
        # 枚举 a
        for first in range(n):
            # 需要和上一次枚举的数不相同
            if first > 0 and nums[first] == nums[first - 1]:
                continue
            # c 对应的指针初始指向数组的最右端
            third = n - 1
            target = -nums[first]
            # 枚举 b
            for second in range(first + 1, n):
                # 需要和上一次枚举的数不相同
                if second > first + 1 and nums[second] == nums[second - 1]:
                    continue
                # 需要保证 b 的指针在 c 的指针的左侧
                while second < third and nums[second] + nums[third] > target:
                    third -= 1
                # 如果指针重合,随着 b 后续的增加
                # 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
                if second == third:
                    break
                if nums[second] + nums[third] == target:
                    ans.append([nums[first], nums[second], nums[third]])
        
        return ans

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/3sum/solution/san-shu-zhi-he-by-leetcode-solution/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

思想一样,就是在外层再套一个循环。

3.四数之和

题目:https://leetcode-cn.com/problems/4sum/

整体思路一样,题解可以看看,多了个剪枝操作(通过判断情况筛选掉不必要的循环)

官方题解:

https://leetcode-cn.com/problems/4sum/solution/si-shu-zhi-he-by-leetcode-solution/https://leetcode-cn.com/problems/4sum/solution/si-shu-zhi-he-by-leetcode-solution/

4.N数之和 

道理一样,就是在外层套循环。然后将最内的两层循环改为双指针操作。

标签:剪枝,target,nums,python,j1,--,second,first,指针
来源: https://blog.csdn.net/kuabiku/article/details/122777071

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有