以下是“亚马逊”向我提出的面试问题。我还没有想出一个优化的解决方案。
问题陈述:
给出一个未排序的整数数组n。 如果匹配的任何整数与目标值相加,则返回'true',否则返回false 。
注意:
1)'n' could be 1000 or 10,000.
2) Target value could be 'negative'
3) It may be addition of any 'k' integers (not only two) , where k<=n.
测试条件:
i/p:- Array A[]= {6,7,3,0,12,-5,-6,100}
Target = 8
o/p:- TRUE
As, 6+7+(-5)=8
如果我们尝试线性或正常运行,则需要 O(2 ^ n)时间复杂度。
所以我正在寻找能够更好地优化这个问题的任何方法或算法。
提前谢谢!
答案 0 :(得分:9)
子集和问题是一个众所周知的NP完全问题。在这里,我将假设您正在寻找任何数字总和以达到目标(如果您实际上只查找两个数字,那么使用计数哈希表的五行解决方案在O(n)中运行)时间)。
有两种基本方法。第一个是测试每个可能的子序列。正如您已经观察到的那样,需要O(2 n )时间(指数),如果n是1000,这是难以处理的。
第二个是跟踪从列表的前缀可以获得的总和。这是一种非常简单的方法,如果整数有界,则效果很好。举例来说,如果输入是n个k位整数,则它具有计算复杂度O(2 k n 2 )(伪多项式):总和可以得到的最大值是2 k n,因此该表最多有2个 k n 2 条目。这是一种典型的动态编程方法,子问题为T[s][k] = (A[1..k] has a subsequence summing to s)
,最终解决方案由T[target][n]
给出。
这是Python实现这个的解决方案:
def subset_sum(A, target):
T = {0} # T[s][0] = (TRUE iff s == 0)
for i in A:
T |= {x + i for x in T}
return target in T
示例:
>>> subset_sum([-5,6,7,1,0,12,5,-6,100], 13)
True
>>> subset_sum([95, -120, 22, 14491], 13)
False
奖金:如果你很好奇,这里是配对问题的解决方案。它在O(n)时间运行并告诉您阵列是否有两个数字相加到目标。
from collections import Counter
def pair_sum(A, t):
C = Counter(A)
for k,v in C.iteritems():
if t == k+k and v > 1: return True # k is in the array twice
elif t != k+k and t-k in C: return True
return False
示例:
>>> pair_sum([3,3,3,4], 13)
False
>>> pair_sum([3,3,3,10], 13)
True
>>> pair_sum([7,7,2], 14)
True
>>> pair_sum([7,14,2], 14)
False
答案 1 :(得分:1)
注意这个答案仍然是有用的,所以我保留了它,但在OP编辑之后,它的相关性较低。
以下是我如何使用名为'Hashing'的概念在O(n)
运行时复杂度和O(n)
空间复杂度中解决它。 (其中n是数组的大小)
让我们拨打我想要的号码d
首先,我会创建某种HashTable
(一个键值存储)。
HashMaps有O(1)
insert,get和contains。你可以阅读它们here
然后我会将每个对象放在哈希映射中的单元格d对象中。在我检查下一个数字x之前,我会检查哈希映射是否包含单元格x的值。如果确实如此,我们找到了匹配。
这是一些伪代码(我认为这对于一般答案比C代码更好)
CheckIfTwoNumbersComplementTo(d,arr)
map <-- new HashTable
for each number x in Arr
if(map contains a key for x)
return true
else
add d-x to map if it is not already in map
return false
答案 2 :(得分:0)
如何对数组进行排序,并为每个元素计算目标值所需的对并搜索它?这将导致排序成本+加上每个二进制搜索。