两数之和
简单题,利用字典保存数和位置,查找target-n
def twoSum(self, nums, target):
d = {}
for i,num in enumerate(nums):
if target-num in d:
return d.get(target-num),i
else:
d[num] = i
三数之和
对数组进行排序,固定一个值,设置头尾两个指针,和小于移动头指针,和大于0移动尾指针。
一开始 将指针设置在固定值的两侧,由于探测了过多的重复情况导致超过时间限制。
后改为将指针,设在固定值之后,更改固定值时如果与之前相同就跳过。
当发现满足条件的组合时,也判断头尾指针与下一个值是否相同,相同则跳过,减少的操作次数
def threeSum(self,nums):
nums.sort()
ret = []
for i,x in enumerate(nums):
if x == nums[i-1] and i>0:
continue
j = i+1
k = len(nums)-1
while j<k:
if nums[i]+nums[j]+nums[k] < 0:
j+=1
elif nums[i]+nums[j]+nums[k] > 0:
k-=1
else:
ans = [nums[i],nums[j],nums[k]]
ret.append(ans)
j+=1
k-=1
while j<k and nums[j] == nums[j-1]:
j+=1
while j<k and nums[k] == nums[k+1]:
k-=1
return ret
最接近的三数和
思路同上,注意接近时有可能大于目标值,或小于目标值。需要比较绝对值。
def threeSumClosest(self, nums, target):
nums.sort()
ans = 0
min = 2 ** 31 - 1
for i, x in enumerate(nums):
if x == nums[i - 1] and i > 0:
continue
j = i + 1
k = len(nums) - 1
while j < k:
if abs(target - (nums[i] + nums[j] + nums[k])) < min:
ans = nums[i] + nums[j] + nums[k]
min = abs(target - (nums[i] + nums[j] + nums[k]))
if nums[i] + nums[j] + nums[k] < target:
j += 1
while j < k and nums[j] == nums[j - 1]:
j += 1
elif nums[i] + nums[j] + nums[k] > target:
k -= 1
while j < k and nums[k] == nums[k + 1]:
k -= 1
else:
return target
return ans
四(n)数求和
遇到四数求和时,一开始以三数求和为基础,头尾分别固定一个值,利用对撞指针求解。
但是之后遇到5,6,7个数求和时,问题将变得更复杂。
考虑变为子集问题递归求解 找到长度为n 和为target的子集。
对于最后两组测试数据 会超过时间限制
考虑子集已排序,对于长度小于4时 如果填充当前项 已经超过 target 或者填充最大项仍小于target的部分 直接跳过;长度大于4 也跳过。优化后最后一组测试用例仍超时。
由于子集问题递归的过程相当于n重循环 对最后两重循环 也就是选择好2个数以后,用对撞指针减少一次循环。通过测试
def fourSum(self, nums, target):
nums.sort()
if len(nums)<4 or nums[-1]*4<target:
return []
def sub(nums,r,ret,target,n):
if n<2:
return
if n == 2:
i = 0
j = len(nums)-1
while i<j:
if nums[i] + nums[j] < target:
i+=1
elif nums[i] + nums[j] > target:
j-=1
else:
temp = r[:]
temp.append(nums[i])
temp.append(nums[j])
ret.append(temp)
while i<j and nums[i] == nums[i-1]:
i+=1
i+=1
while i<j and nums[j] == nums[j-1]:
j-=1
j-=1
return
else:
for i,x in enumerate(nums[0:len(nums)-n+1]):
if i>0 and x==nums[i-1]:
continue
temp = r[:]
a = n * nums[-1]
b = n * x
if a < target or b > target:
break
temp.append(x)
sub(nums[i+1:],temp[:],ret,target-x,n-1)
ret = []
sub(nums,[],ret,target,4)
return ret
此方法应适用于 n>2的求和问题