/主要为了优化时间复杂度,尽量减少循环,用到双指针,前后同时进行。这里需要注意执行效率,当先验判断过多“if”语句时,会影响程序执行效率,因此尽量减少多个并行if的条件判断句
*需注意在双指针循环中,跳过重复元素while小循环里面还要写一遍start<end的先验条件,否则会报错index out of rage
多数求和整体思路如下:
1.排序+双指针:
#多个并行的if语句大量引入会严重影响程序的执行效率,因此因尽量避免
class Solution:
def threesum(self,nums):
res=[]#用来储存要输出的元素对
#排序后如果存在a+b+c==0的情况,那么肯定数组有正有负,负数在左,正数在右
nums=sorted(nums)
n=len(nums)
#当数组长度小于3时、
if n<3:
return []
# 特殊情况全为0,快速判断
#if nums==[0]*n:
# return [[0,0,0]]
# 排序后从小到大,如果最小值>0或者最大值<0,那么都不可能存在加和为0的数组
#if nums[0]>0 or nums[n-1]<0:
# return res
for i in range(n):
#做一个简单判断,因为for循环从顺序i=0开始执行,因此为简化计算,
#先验判断首位循环是否符合条件,若不符合,则直接跳出循环
#末尾循环i=n-1值判断无太大意义,因为已经执行到程序的最后一次循环
if nums[i] > 0:
return res
# 防止指针溢出,从第二个数字开始判断,contiue表示满足if时候跳出当前小循环
if (i>0 and nums[i]==nums[i-1]):
continue
#双指针头尾检索,加快运行速率,有点类似快速排序
start=i+1
end=n-1
while (start<end):
if nums[i]+nums[start]+nums[end]==0:
res.append([nums[i], nums[start], nums[end]])
# 跳过一些特殊情况,比如相同元素,避免输出重复解
while (start<end and nums[start]==nums[start+1]):
start += 1
while (start<end and nums[end] == nums[end-1]):
end -= 1
# 第一个指针数字已经固定,移动剩下俩个指针,加和固定,同时移动
start += 1
end -= 1
#左边为负,整体和为负数,则说明偏向负值,则左指针+1
elif nums[i]+nums[start]+nums[end]<0:
start += 1
#右边为正,整体和为正数,则说明偏向正值,则右指针-1
else:
#nums[i]+nums[start]+nums[end]>0:
end -= 1
return res
if __name__=='__main__':
#nums = [-1, 0, 1, 2, -1, -4]
nums=[0,0,0,0]
#nums=[-1,-2,-3]
#[[-1, -1, 2], [-1, 0, 1]]
a=Solution()
print(a.threesum(nums))
2.枚举(排列组合)+求和判断+去除重复值
(用到高级的生成器,迭代器等)
【待补充】
多数求和:原理类似,比如双指针+排序,四数求和起多了一层循环,类似方法全可以如下,再最外层循环中进行一些项的排除,减少迭代:
class Solution:
def fourSum(self, nums: List[int], target: int) -> List[List[int]]:
quadruplets = list()
if not nums or len(nums) < 4:
return quadruplets
nums.sort()
length = len(nums)
for i in range(length - 3):
if i > 0 and nums[i] == nums[i - 1]:
continue
if nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target:
break
if nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target:
continue
for j in range(i + 1, length - 2):
if j > i + 1 and nums[j] == nums[j - 1]:
continue
if nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target:
break
if nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target:
continue
left, right = j + 1, length - 1
while left < right:
total = nums[i] + nums[j] + nums[left] + nums[right]
if total == target:
quadruplets.append([nums[i], nums[j], nums[left], nums[right]])
while left < right and nums[left] == nums[left + 1]:
left += 1
left += 1
while left < right and nums[right] == nums[right - 1]:
right -= 1
right -= 1
elif total < target:
left += 1
else:
right -= 1
return quadruplets