题目
nSUM问题是指,在一个数组中,找出n个数相加和等于给定的数,返回数的下标列表。
2sum
字典法
建立 {元素:下标} 字典,遍历数组,判断target-x是否在字典里,如果在则返回结果,如果不在字典里就把当前元素加入字典。不在一开始遍历数组建字典,为了避免重复元素抵消下标,比如[2,2],只能存一个下标。
时间复杂度为O(n)
class Solution:
def twoSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[int]
"""
hashmap = {}
for i, x in enumerate(nums):
y = target - x
if y in hashmap:
return hashmap[y],i
hashmap[x]=i
排序,对撞指针
使用两个指针一个在头一个在尾,将收尾相加求和与target比较,因为有序,如果大于target就把i 右移 ,如果小于就把j 左移。
时间复杂度是O(nlogn),主要在于排序的时间
def twoSum1(self, numbers, target):
"""
:type numbers: List[int]
:type target: int
:rtype: List[int]
"""
l = len(numbers)
i, j = 0, l-1
while i < j:
if numbers[i] + numbers[j] == target:
return i, j
elif numbers[i] + numbers[j] > target:
j -= 1
else:
i += 1
3sum
对于排序后的数组遍历,对每个位置都从它的后一个元素和末尾一个元素向中间集中,如果和为0就添加到结果数组中。这里需要注意的地方是需要跳过相同的数字,因为同样的数字组合只能出现一次。
时间复杂度是O(N^2),空间复杂度是O(1)
class Solution(object):
def threeSum(self, nums):
"""
:type nums: List[int]
:rtype: List[List[int]]
"""
N = len(nums)
nums.sort()
res = []
for t in range(N - 2):
if t > 0 and nums[t] == nums[t - 1]:#和前一个数相等,跳过
continue
i, j = t + 1, N - 1
while i < j:
_sum = nums[t] + nums[i] + nums[j]
if _sum == 0:
res.append([nums[t], nums[i], nums[j]])
i += 1
j -= 1
while i < j and nums[i] == nums[i - 1]:#和前一个数相等,跳过
i += 1
while i < j and nums[j] == nums[j + 1]:#和后一个数相等,跳过
j -= 1
elif _sum < 0:
i += 1
else:
j -= 1
return res
另一种思路是,最外层遍历一遍,等于选出一个数, 之后的数组中转化为找和为target-nums[i]的2SUM问题,调用2sum函数。
4sum
总结一下K-sum题目。
- 首先先排序
- 然后用K - 2个指针做O(N^(K - 2))的遍历
- 剩下2个指针从第2步的剩余区间里面找,找的方式是使用两个指针p, q分别指向剩余区间的首尾,判断两个指针的和与target - 第2步的和的关系,对应的移动指针。即如果两个数的和大了,那么,q–;如果两个数的和小了,那么,p++;等于的话,输出结果。要时刻注意p < q.
- 用p,q查找剩余区间结束之后,需要移动前面的K-2个值,这里需要在移动的过程中做个去重,找到和前面不同的值继续查找剩余区间。
时间复杂度是O(N^3),空间复杂度是O(1).
class Solution(object):
def fourSum(self, nums, target):
"""
:type nums: List[int]
:type target: int
:rtype: List[List[int]]
"""
N = len(nums)
nums.sort()
res = []
i = 0
while i < N - 3:
j = i + 1
while j < N - 2:
k = j + 1
l = N - 1
remain = target - nums[i] - nums[j]
while k < l:
if nums[k] + nums[l] > remain:
l -= 1
elif nums[k] + nums[l] < remain:
k += 1
else:
res.append([nums[i], nums[j], nums[k], nums[l]])
while k < l and nums[k] == nums[k + 1]:
k += 1
while k < l and nums[l] == nums[l - 1]:
l -= 1
k += 1
l -= 1
while j < N - 2 and nums[j] == nums[j + 1]:
j += 1
j += 1 # 重要
while i < N - 3 and nums[i] == nums[i + 1]:
i += 1
i += 1 # 重要
return res
参考:https://blog.csdn.net/fuxuemingzhu/article/details/83543296