文章目录

  • 1.两数之和—two sum
    • 1.1 两数之和—返回元素
    • 1.2 两数之和—返回多对元素
  • 167.两数之和 II - 输入有序数组
  • 15.三数之和
  • 16. 最接近的三数之和
  • 18.四数之和
  • 总结

1.两数之和—two sum

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出和为目标值的那两个整数,并返回它们的数组下标。数组中同一个元素在答案里不能重复出现。

这道题有三种解法:
a.暴力解法

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:"""暴力解法:时间复杂度为O(n^2)"""for i in range(len(nums)-1):for j in range(i+1,len(nums)):  # 元素不能重复使用if nums[i] + nums[j] == target:return [i,j]

b.哈希表解法
创建一个哈希表,对于每一个x,我们首先查询哈希表中是否存在 target - x,然后将x插入到哈希表中,即可保证不会让x和自己匹配

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:"""哈希表:时间复杂度为O(n)"""map = {}for i in range(len(nums)):if target - nums[i] in map:return [map[target-nums[i]],i]else:map[nums[i]] = i

双指针解法
两个指针分别从左从右开始扫描,每次判断这两个数相加是不是target,如果小了,那就把左边的指针向右移,如果大了,右指针左移

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:"""双指针解法:时间复杂度为O(n)"""arr = nums.copy()    # 保留原索引arr.sort()left = 0   # 左指针right = len(nums) - 1   # 右指针while left < right:if arr[left] + arr[right] > target:right -= 1elif arr[left] + arr[right] < target:left += 1else:break# 循环结束条件:left = right,或者nums[left] + nums[right] = targetresult = []if left == right:return "no solution"else:for k in range(len(nums)):if nums[k] == arr[left] or nums[k] == arr[right]:result.append(k)return result

1.1 两数之和—返回元素

如果假设输入一个数组nums和一个目标和target,请你返回nums 中能够凑出target的两个元素的值,比如输入nums =[5,3,1,6], target = 9,那么算法返回两个元素[3,6]。可以假设只有且仅有一对儿元素可以凑出target。

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:"""双指针解法:时间复杂度为O(n)"""arr = numsarr.sort()left = 0   # 左指针right = len(nums) - 1   # 右指针while left < right:if arr[left] + arr[right] > target:right -= 1elif arr[left] + arr[right] < target:left += 1else:return [arr[left],arr[right]]# 循环结束条件:left = right,或者nums[left] + nums[right] = target

1.2 两数之和—返回多对元素

nums 中可能有多对儿元素之和都等于target,请你的算法返回所有和为target的元素对儿,其中不能出现重复
比如说输入为nums =[1,3,1,2,2,3], target = 4,那么算法返回的结果就是 : [[1,3],[2,2]]
由于不能出现重复,所以需要把相同的元素跳过去

class Solution:def twoSum(self, nums: List[int], target: int) -> List[int]:"""双指针解法:时间复杂度为O(nlogn)"""arr = numsarr.sort()result =[]left = 0   # 左指针right = len(nums) - 1   # 右指针# le,ri = arr[left],arr[right]while left < right:if arr[left] + arr[right] > target:right -= 1elif arr[left] + arr[right] < target:left += 1else:result.append([arr[left],arr[right]])# 以下while循环确保不会出现相同的值while left < right and arr[left+1] == arr[left]:left += 1return result# 循环结束条件:left = right

167.两数之和 II - 输入有序数组

给定一个已按照 升序排列 的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。
函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素

具体步骤如下:
1、使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
2、如果两个指针指向元素的和sum == target,那么得到要求的结果;3、如果sum > target,移动较大的元素,使sum 变小一些;如果sum < target,移动较小的元素,使sum变大一些。

class Solution:def twoSum(self, numbers: List[int], target: int) -> List[int]:"""双指针算法:时间复杂度为O(n)"""# 数组已排序,所以省略排序步骤left,right = 0,len(numbers)-1while left < right:if numbers[left] + numbers[right] > target:right -= 1elif numbers[left] + numbers[right] < target:left += 1else:return [left+1,right+1]

15.三数之和

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

a.暴力解法
三层遍历,然后去重

class Solution:def threeSum(self, nums: List[int]) -> List[List[int]]:"""暴力解法:时间复杂度为O(n^3)"""nums.sort()result = []   # 存储元祖for i in range(len(nums)):for j in range(i+1,len(nums)):for k in range(j+1,len(nums)):if nums[i] + nums[j] + nums[k] == 0:# 去重if [nums[i],nums[j],nums[k]] not in result:result.append([nums[i],nums[j],nums[k]])return result

运行会显示超出时间限制

b.双指针法

具体步骤如下:
1、我们可以先对数组进行排序,然后我们选择一个数字做C位,然后我们在这个C位数字的右边进行双指针搜索:
2、从最左边i+1(最小值)和最右边len(nums)-1(最大值)两个数字开始,加上c位,计算总和是否等于0。
如果大于0,说明实力太强了,就把右侧的数字左移一位如果小于0,说明实力太弱了,就把左边的数字右移一位
3、当双指针碰到的时候,这轮循环结束,以该数字为C位的所有可能都已经尝试完毕了。

上面步骤可以概括为:固定一个数字,然后使用双指针遍历来查找另外两个数

class Solution:def threeSum(self, nums: List[int]) -> List[List[int]]:"""双指针解法:固定一个数字,然后循环遍历寻找另外两个数,时间复杂度为O(n^2)"""nums.sort()  # 升序排序result = []for i in range(len(nums)):# 去重if i > 0 and nums[i] == nums[i-1]:continueleft,right = i+1,len(nums)-1  # 左右指针while left < right:if nums[i] + nums[left] + nums[right] > 0:right -= 1elif nums[i] + nums[left] + nums[right] < 0:left += 1else:result.append([nums[i],nums[left],nums[right]])# 去重while left < right and nums[left] == nums[left+1]:left += 1# while left < right and nums[right] == nums[right+1]:#right -= 1left += 1right -= 1return result

16. 最接近的三数之和

给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。
假定每组输入只存在唯一答案。

示例:

输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。

具体步骤:

1、在数组nums 中,进行遍历,每遍历一个值利用其下标i,形成一个固定值nums[i]。
2、使用前指针指向 left = i+1处,后指针指向right = len(nums) - 1处,也就是结尾处,根据sums = nums[i]+ nums[Ieft]+ nums[right]的结果,判断sums与目标 target 的距离,如果更近则更新结果a。
3、因为数组有序,如果sums > target则 right -= 1,如果sums < target则 left+= 1,如果sums == target 则说明距离为0,直接返回结果。

上述步骤与三数之和的区别在于:需要比较sums与target的距离,距离变小时,需要更新,如果为0,则直接返回结果

class Solution:def threeSumClosest(self, nums: List[int], target: int) -> int:"""双指针解法:时间复杂度为O(n^2)"""nums.sort()  # 排序# 初始化a = abs(nums[0]+nums[1]+nums[2]-target)res = nums[0]+nums[1]+nums[2]for i in range(len(nums)):# 定义左右指针left,right = i+1,len(nums)-1while left < right:sums  = nums[i] +nums[left] + nums[right]# 距离进行比较,如果更小,则进行更新if abs(sums-target) < a:a = abs(nums[i] +nums[left] + nums[right] - target)res = nums[i] +nums[left] + nums[right]if sums > target:right -= 1elif sums < target:left += 1else:return sumsreturn res

18.四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:答案中不可以包含重复的四元组。

由于三数之和暴力解法就已经超时,这里直接跳过暴力解法
a.双指针解法

具体步骤如下:
1、使用两重循环分别枚举前两个数,然后在两重循环枚举到的数之后使用双指针枚举剩下的两个数。假设两重循环枚举到的前两个数分别位于下标i和j,其中i<j。
2、初始时,左右指针分别指向下标j+1和下标n-1。3、每次计算四个数的和,并进行如下操作:
如果和等于target,则将枚举到的四个数加到答案中,然后将左指针右移直到遇到不同的数,将右指针左移直到遇到不同的数;
如果和小于target,则将左指针右移一位;
如果和大于target,则将右指针左移一位。

上述步骤可以概括为:在三数之和的基础上在固定一个元素,在二数之和的基础上固定两元素

具体实现时,还可以进行一些剪枝操作:
1、在确定第一个数之后,如果nums[i]+ nums [i+1]+nums[i+2]+nums[i+3]>target说明此时剩下的三个数无论取什么值,四数之和一定大于target,因此退出第一重循环break
2、在确定第一个数之后,如果nums[i]+nums[n-3]+nums[n-2]+nums[n-1]<target,说明此时剩下的三个数无论取什么值,四数之和一定小于target,因此第一重循环直接进入下一轮,枚举nums[i+1];
3、在确定前两个数之后,如果nums[i]+nums[j]+nums[j+1]+nums[j+2]>target,说明此时剩下的两个数无论取什么值,四数之和一定大于target,因此退出第二重循环;
4、在确定前两个数之后,如果nums[i]+nums[n-3]+nums[n-2]+nums[n-1]<target,说明此时剩下的两个数无论取什么值,四数之和一定小于target,因此第二重循环直接进入下一轮,枚举nums[j+1]。

class Solution:def fourSum(self, nums: List[int], target: int) -> List[List[int]]:res = []# 数组元素个数小于4时,直接返回[]if not nums or len(nums) < 4:return resnums.sort()   # 排序n = len(nums)# 固定第一个元素—第一重循环for i in range(n-3):# 去重if i > 0 and nums[i] == nums[i-1]:continue# 剪枝if nums[i]+nums[i+1]+nums[i+2]+nums[i+3] > target:breakif nums[i]+nums[n-1]+nums[n-2]+nums[n-3] < target:continue# 固定第二个元素—第二重循环for j in range(i+1,n-2):# 去重if j > i+1 and nums[j] == nums[j-1]:continue# 剪枝if nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target:breakif nums[i]+nums[j]+nums[n-1]+nums[n-2] < target:continue"""使用双指针解法处理后面两个元素"""left,right = j+1,n-1while left < right:if nums[i]+nums[j]+nums[left]+nums[right] > target:right -= 1elif nums[i]+nums[j]+nums[left]+nums[right] < target:left += 1else:res.append([nums[i],nums[j],nums[left],nums[right]])# 去重while left < right and nums[left+1] == nums[left]:left += 1while left < right and nums[right-1] == nums[right]:right -= 1left += 1right -= 1return res

总结

  据此类推,n数之和类型问题就可以这样解答

循环固定n-2个数,剩下两个数利用双指针解法来寻找


如果对您有帮助,麻烦点赞关注,这真的对我很重要!!!如果需要互关,请评论或者私信!


Leetcode—5.n sum 问题python解答相关推荐

  1. leetcode 1556. Thousand Separator(python)

    leetcode 1556. Thousand Separator(python) 描述 Given an integer n, add a dot (".") as the th ...

  2. 蓝桥杯书号验证——python解答

    题目如下 2004年起,国际ISBN中心出版了<13位国际标准书号指南>. 原有10位书号前加978作为商品分类标识:校验规则也改变. 校验位的加权算法与10位ISBN的算法不同,具体算法 ...

  3. 计蒜客难题题库之一 泥塑课 python解答

    计蒜客挑战难题之一 泥塑课 python解答 题目: 小米是一个幼儿园老师,每学期的泥塑课上,她都会给每个学生发不超过250立方厘米的等量橡皮泥,教大家做泥塑.在上课过程中,她发现每个班都恰好有一个小 ...

  4. leetcode 1005 Maximize Sum Of Array After K Negations

    leetcode 1005 Maximize Sum Of Array After K Negations 1.题目描述 2.解题思路 3.Python代码 1.题目描述 给定一个整数数组 A,我们只 ...

  5. [勇者闯LeetCode] 1. Two Sum

    [勇者闯LeetCode] 1. Two Sum Description Given an array of integers, return indices of the two numbers s ...

  6. [勇者闯LeetCode] 112. Path Sum

    [勇者闯LeetCode] 112. Path Sum Description Given a binary tree and a sum, determine if the tree has a r ...

  7. [云炬python学习笔记]Numpy中内置函数min(),max(),sum()与Python中内置函数min(),max(),sum()性能对比分析

    众所周知,Python有许多内置函数(例如min(),max(),sum()),Numpy也有自己的内置函数(np.min(),np.max(),np.sum()).由于Numpy的函数是在编译码中执 ...

  8. LeetCode 75. Sort Colors (python一次遍历,模拟三路快排)

    LeetCode 75. Sort Colors (python一次遍历,模拟三路快排) 题目分析: 本题需要实现数字只包含0,1,2的排序,并且要求一次遍历. 由于只用把数字隔离开,很容易想到快排的 ...

  9. leetcode 304. Range Sum Query 2D - Immutable |304. 二维区域和检索 - 矩阵不可变(二维前缀和问题)

    题目 https://leetcode.com/problems/range-sum-query-2d-immutable/ 题解 本题是 medium 难度,二维前缀和问题.相似题目有: Easy: ...

  10. leetcode刷题可以用python吗_LeetCode刷题——第四天(python)

    每天选壁纸做封面这个环节是我最喜欢的,今天的题目是比较经典又十分简单的一道题. 第四天--第四题(回文数) 请看题:判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整 ...

最新文章

  1. skia库的3D变换研究
  2. xx is not in the sudoers file 问题解决
  3. 【语音SBC算法】基于正交滤波器组的语音SBC算法设计与实现
  4. Linux中文显示乱码?如何设置centos显示中文
  5. android gradle自定义钉钉群提醒
  6. flutter web:lottie jssdk报错处理
  7. Redis持久化方式~RDB 持久化和AOF 持久化
  8. Javascript:call(),apply()和bind()
  9. could not insert:
  10. 数据库实验一、实验二、实验三、实验四
  11. <论文阅读>TARE: A Hierarchical Framework for Efficiently Exploring Complex 3D Environments
  12. 电子设计(4)高电平、低电平复位电路
  13. Latex去掉proof后面显示的小白框 (\qed)
  14. MATLAB离散点边界曲线的绘制
  15. python123第四周_百度杯十月第四周WriteUp
  16. MS-SQL Server 基础类 - SQL语句
  17. 别让STAR原则的简历毁了你的前途!
  18. OMA-DM协议资料汇总
  19. 指定ip地址和端口号登录mysql数据库_防火墙规则,指定ip访问mysql数据库3306端口...
  20. UVA 1633 Dyslexic Gollum

热门文章

  1. Android Activity launchMode研究
  2. [悟] 因上努力,果上随缘(转)
  3. 802.11相关术语及其设计(二)
  4. 第四十四篇 面向对象高阶
  5. 第2次作业 -- 熟悉 JUnit 测试
  6. BUAA软工第0次作业
  7. mysql 的命令行操作
  8. API文档自动生成,Swagger的配置
  9. Python学习笔记11:标准库之文件管理(os包,shutil包)
  10. Ruby IDE及相关书籍