Leetcode—5.n sum 问题python解答
文章目录
- 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解答相关推荐
- leetcode 1556. Thousand Separator(python)
leetcode 1556. Thousand Separator(python) 描述 Given an integer n, add a dot (".") as the th ...
- 蓝桥杯书号验证——python解答
题目如下 2004年起,国际ISBN中心出版了<13位国际标准书号指南>. 原有10位书号前加978作为商品分类标识:校验规则也改变. 校验位的加权算法与10位ISBN的算法不同,具体算法 ...
- 计蒜客难题题库之一 泥塑课 python解答
计蒜客挑战难题之一 泥塑课 python解答 题目: 小米是一个幼儿园老师,每学期的泥塑课上,她都会给每个学生发不超过250立方厘米的等量橡皮泥,教大家做泥塑.在上课过程中,她发现每个班都恰好有一个小 ...
- leetcode 1005 Maximize Sum Of Array After K Negations
leetcode 1005 Maximize Sum Of Array After K Negations 1.题目描述 2.解题思路 3.Python代码 1.题目描述 给定一个整数数组 A,我们只 ...
- [勇者闯LeetCode] 1. Two Sum
[勇者闯LeetCode] 1. Two Sum Description Given an array of integers, return indices of the two numbers s ...
- [勇者闯LeetCode] 112. Path Sum
[勇者闯LeetCode] 112. Path Sum Description Given a binary tree and a sum, determine if the tree has a r ...
- [云炬python学习笔记]Numpy中内置函数min(),max(),sum()与Python中内置函数min(),max(),sum()性能对比分析
众所周知,Python有许多内置函数(例如min(),max(),sum()),Numpy也有自己的内置函数(np.min(),np.max(),np.sum()).由于Numpy的函数是在编译码中执 ...
- LeetCode 75. Sort Colors (python一次遍历,模拟三路快排)
LeetCode 75. Sort Colors (python一次遍历,模拟三路快排) 题目分析: 本题需要实现数字只包含0,1,2的排序,并且要求一次遍历. 由于只用把数字隔离开,很容易想到快排的 ...
- leetcode 304. Range Sum Query 2D - Immutable |304. 二维区域和检索 - 矩阵不可变(二维前缀和问题)
题目 https://leetcode.com/problems/range-sum-query-2d-immutable/ 题解 本题是 medium 难度,二维前缀和问题.相似题目有: Easy: ...
- leetcode刷题可以用python吗_LeetCode刷题——第四天(python)
每天选壁纸做封面这个环节是我最喜欢的,今天的题目是比较经典又十分简单的一道题. 第四天--第四题(回文数) 请看题:判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整 ...
最新文章
- skia库的3D变换研究
- xx is not in the sudoers file 问题解决
- 【语音SBC算法】基于正交滤波器组的语音SBC算法设计与实现
- Linux中文显示乱码?如何设置centos显示中文
- android gradle自定义钉钉群提醒
- flutter web:lottie jssdk报错处理
- Redis持久化方式~RDB 持久化和AOF 持久化
- Javascript:call(),apply()和bind()
- could not insert:
- 数据库实验一、实验二、实验三、实验四
- <论文阅读>TARE: A Hierarchical Framework for Efficiently Exploring Complex 3D Environments
- 电子设计(4)高电平、低电平复位电路
- Latex去掉proof后面显示的小白框 (\qed)
- MATLAB离散点边界曲线的绘制
- python123第四周_百度杯十月第四周WriteUp
- MS-SQL Server 基础类 - SQL语句
- 别让STAR原则的简历毁了你的前途!
- OMA-DM协议资料汇总
- 指定ip地址和端口号登录mysql数据库_防火墙规则,指定ip访问mysql数据库3306端口...
- UVA 1633 Dyslexic Gollum