我有这样的问题
给出一个由 n 个整数组成的数组
nums
,nums
中是否存在元素 a , b 使得 a + b = 10?在数组中找到给出目标总和的所有唯一对。注意:
解决方案集不能包含重复的对。
示例:
Given nums = [4, 7, 6, 3, 5], target = 10 because 4+ 6= 7+ 3 = 10 return [[4, 6], [7,3]]
我的解决方案:
class SolutionAll: #Single Pass Approach
def twoSum(self, nums, target) -> List[List[int]]:
"""
:type nums: List[int]
:type target: int
"""
nums.sort()
nums_d:dict = {}
couples = []
if len(nums) < 2:
return []
for i in range(len(nums)):
if i > 0 and nums[i] == nums[i-1]: continue #skip the duplicates
complement = target - nums[i]
if nums_d.get(complement) != None:
couples.append([nums[i], complement])
nums_d[nums[i]] = i
return couples
TestCase结果:
target: 9
nums: [4, 7, 6, 3, 5]
DEBUG complement: 6
DEBUG nums_d: {3: 0}
DEBUG couples: []
DEBUG complement: 5
DEBUG nums_d: {3: 0, 4: 1}
DEBUG couples: []
DEBUG complement: 4
DEBUG nums_d: {3: 0, 4: 1, 5: 2}
DEBUG couples: [[5, 4]]
DEBUG complement: 3
DEBUG nums_d: {3: 0, 4: 1, 5: 2, 6: 3}
DEBUG couples: [[5, 4], [6, 3]]
DEBUG complement: 2
DEBUG nums_d: {3: 0, 4: 1, 5: 2, 6: 3, 7: 4}
DEBUG couples: [[5, 4], [6, 3]]
result: [[5, 4], [6, 3]]
.
target: 2
nums: [0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1]
DEBUG complement: 2
DEBUG nums_d: {0: 0}
DEBUG couples: []
DEBUG complement: 1
DEBUG nums_d: {0: 0, 1: 9}
DEBUG couples: []
result: []
该解决方案适用于[4、7、6、3、5],但失败于[0,0,0,0,0,0,0,0,0,1,1,1,1,1, 1]
我试图删除重复项,但是得到了意外的结果。
如何通过这种“一站式”解决方案解决问题?
答案 0 :(得分:2)
您的代码存在的问题是它会跳过重复的数字,而不是重复的 pairs 。因为
if i > 0 and nums[i] == nums[i-1]: continue #skip the duplicates
您的代码从不尝试对1 + 1 = 2
求和。
这是一个O(n)
复杂性的可行解决方案:
from collections import Counter
def two_sum(nums, target):
nums = Counter(nums) # count how many times each number occurs
for num in list(nums): # iterate over a copy because we'll delete elements
complement = target - num
if complement not in nums:
continue
# if the number is its own complement, check if it
# occurred at least twice in the input
if num == complement and nums[num] < 2:
continue
yield (num, complement)
# delete the number from the dict so that we won't
# output any duplicate pairs
del nums[num]
>>> list(two_sum([4, 7, 6, 3, 5], 10))
[(4, 6), (7, 3)]
>>> list(two_sum([0, 0, 0, 1, 1, 1], 2))
[(1, 1)]
另请参阅:
答案 1 :(得分:1)
不确定解决方案出了什么问题(也不知道解决方案有什么问题),但是您可以通过“漂亮的Python方式”轻松实现这一目标:
def func(nums,target):
return [(a,b) for a in nums for b in nums if a+b == target]
假定两个仅在元素顺序上不同的元组是唯一的,并且一个元素可以在同一元组中使用两次。如果问题的定义不正确,则可以从返回的值中过滤出这些元组。
答案 2 :(得分:0)
编辑:请参见下面的讨论。
from itertools import combinations
list(set([(a,b) for a,b in combinations(sorted(nums),2) if a+b == target]))
这也会删除重复项。
答案 3 :(得分:0)
其他版本:
>>> nums = [4, 7, 6, 3, 5]
>>> target = 9
>>> set((a, target-a) for a in nums if target-a in set(nums))
{(4, 5), (5, 4), (3, 6), (6, 3)}
对于a
中的每个元素nums
,如果target-a
中也有nums
,则我们有:
a + target-a = target
(显而易见); a
和target-a
都在nums
中。由于我们遍历了每个a
,因此我们获得了所有解决方案。
要消除重复的(x, y)
和(y, x)
:
>>> set((a, target-a) for a in nums if 2*a<=target and target-a in set(nums))
{(4, 5), (3, 6)}
因为2*a <= target
等效于a <= target-a
。当a > target-a
和要求的条件都满足时,我们有一个先前的b = target-a
,因此(b, target-b)
是一个解决方案。