我看到一个面试问题如下: 给出一个未排序的整数数组A和一个整数I,找出A的任何两个成员是否加起来。
任何线索?
时间复杂度应该更低
答案 0 :(得分:22)
将元素插入哈希表。
插入x
时,请检查I-x
是否已存在。 O(n)
预计时间。
否则,将数组升序排序(从索引0到n-1)。有两个指针,一个是最大值,一个是最小值(分别称为M和m)。
If a[M] + a[m] > I then M--
If a[M] + a[m] < I then m++
If a[M] + a[m] == I you have found it
If m > M, no such numbers exist.
答案 1 :(得分:8)
如果你有整数所在的范围,你可以使用类似计数的解决方案来扫描数组并计算数组。例如,你有整数
input = [0,1,5,2,6,4,2]
你创建一个这样的数组:
count = int[7]
(Java,C#等)适用于计算0到6之间的整数。
foreach integer in input
count[i] = count[i] + 1
这将为您提供数组[1,1,2,0,1,1,1]
。现在你可以扫描这个数组(一半),并检查是否有整数加起来i
的整数,如
for j = 0 to count.length - 1
if count[j] != 0 and count[i - j] != 0 then // Check for array out-of-bounds here
WUHUU! the integers j and i - j adds up
总的来说,这个算法给你O(n + k)
,其中n来自扫描长度为n的输入,k是对长度为k的计数数组的扫描(0和k-1之间的整数)。这意味着,如果n > k
,则您可以获得有保证的O(n)
解决方案。
答案 2 :(得分:7)
X
中的每个元素A
,执行I-X
的二进制搜索。如果I-X
位于A
,我们就有解决方案。这是O(nlogn)
。
如果A
包含给定(足够小)范围内的整数,我们可以使用技巧O(n)
:
V
。对于X
中的每个元素A
,我们会增加V[X]
。V[X]
时,我们还会检查V[I-X]
是否为>0
。如果是,我们有一个解决方案。答案 3 :(得分:7)
例如,循环并添加可能的数字来设置或散列,如果找到,只需返回它。
>>> A = [11,3,2,9,12,15]
>>> I = 14
>>> S = set()
>>> for x in A:
... if x in S:
... print I-x, x
... S.add(I-x)
...
11 3
2 12
>>>
答案 4 :(得分:3)
public static boolean findSum2(int[] a, int sum) {
if (a.length == 0) {
return false;
}
Arrays.sort(a);
int i = 0;
int j = a.length - 1;
while (i < j) {
int tmp = a[i] + a[j];
if (tmp == sum) {
System.out.println(a[i] + "+" + a[j] + "=" + sum);
return true;
} else if (tmp > sum) {
j--;
} else {
i++;
}
}
return false;
}
答案 5 :(得分:2)
O(n) time and O(1) space
如果对数组进行排序,则存在O(n)时间复杂度的解决方案。
假设是数组
array = {0, 1, 3, 5, 8, 10, 14}
我们的x1 + x2 = k = 13
,所以输出应该是= 5,8
array[ptr1] + array[ptr2]
if sum > k then decrement ptr2 else increment ptr1
同样的事情在这里详细解释。似乎像亚马逊的采访问题 http://inder-gnu.blogspot.com/2007/10/find-two-nos-in-array-whose-sum-x.html
答案 6 :(得分:1)
python中的实现
def func(list,k):
temp={} ## temporary dictionary
for i in range(len(list)):
if(list[i] in temp): ## if temp already has the key just increment its value
temp[list[i]] +=1
else: ## else initialize the key in temp with count as 0
temp[list[i]]=0
if(k-list[i] in temp and ((k/2 != list[i]) or temp[list[i]]>=1)): ## if the corresponding other value to make the sum k is in the dictionary and its either not k/2 or the count for that number is more than 1
return True
return False
输入:
list是一个数字列表(上面的问题中的A)...
k是总和(我在上面的问题中)....
如果列表中的总和等于k且 False ,则函数输出 True
我正在使用一个字典,其键是数组(列表)中的元素,value是该元素的计数(该列表中元素存在的次数)。 平均运行时间复杂度为O(n)。
此实现还处理两个重要的边缘情况:
答案 7 :(得分:0)
for nlogn
:对数组进行排序,对每个元素[0<=j<len A]
进行排序,减去i-A[j]
,并在排序数组中对此元素进行二进制搜索。
hashmap (frequency of no, number)
应该适用于O(n)
。
答案 8 :(得分:0)
for each ele in the array
if (sum - ele) is hashed and hashed value is not equal to index of ele
print ele, sum-ele
end-if
Hash ele as key and index as value
end-for
答案 9 :(得分:0)
PERL实现,用于检测排序数组是否包含两个总和为数字的整数
my @a = (11,3,2,9,12,15);
my @b = sort {$a <=> $b} @a;
my %hash;
my $sum = 14;
my $index = 0;
foreach my $ele (@b) {
my $sum_minus_ele = $sum - $ele;
print "Trace: $ele :: $index :: $sum_minus_ele\n";
if(exists($hash{$sum_minus_ele}) && $hash{$sum_minus_ele} != $index ) {
print "\tElement: ".$ele." :: Sum-ele: ".$sum_minus_ele."\n";
}
$hash{$ele} = $index;
$index++;
}
答案 10 :(得分:0)
这可能通过以下方式实现:在将元素放入hashmap之前,您可以检查元素是否大于所需的总和。如果是,您可以简单地跳过该元素,否则您可以继续将其放入hashmap中。虽然整体时间仍然相同,但算法略有改进。
答案 11 :(得分:0)
这可以使用UNION-FIND算法解决,该算法可以在恒定时间内检查元素是否属于集合。
所以,算法就是这样:
foundsum0 = false;
foreach (el: array) {
if find (-x): foundsum0 = true;
else union (x);
}
FIND和UNION是常数,O(1)。
答案 12 :(得分:0)
这是使用O(n)额外空间的java中的O(n)解决方案。这使用hashSet来实现它
答案 13 :(得分:0)
这是一个考虑重复条目的解决方案。它是用javascript编写的,并假设数组已排序。该解决方案在O(n)时间运行,除变量外不使用任何额外的内存。选择一种选择的排序算法。 (基数O(kn)!)然后通过这个婴儿运行阵列。
var count_pairs = function(_arr,x) {
if(!x) x = 0;
var pairs = 0;
var i = 0;
var k = _arr.length-1;
if((k+1)<2) return pairs;
var halfX = x/2;
while(i<k) {
var curK = _arr[k];
var curI = _arr[i];
var pairsThisLoop = 0;
if(curK+curI==x) {
// if midpoint and equal find combinations
if(curK==curI) {
var comb = 1;
while(--k>=i) pairs+=(comb++);
break;
}
// count pair and k duplicates
pairsThisLoop++;
while(_arr[--k]==curK) pairsThisLoop++;
// add k side pairs to running total for every i side pair found
pairs+=pairsThisLoop;
while(_arr[++i]==curI) pairs+=pairsThisLoop;
} else {
// if we are at a mid point
if(curK==curI) break;
var distK = Math.abs(halfX-curK);
var distI = Math.abs(halfX-curI);
if(distI > distK) while(_arr[++i]==curI);
else while(_arr[--k]==curK);
}
}
return pairs;
}
我在一家大公司的采访中解决了这个问题。他们接受了但不是我。 所以这里适合所有人。
从数组的两侧开始,慢慢向内工作,确保重复计算(如果存在)。
它只计算对,但可以重新编写
享受并且不要忘记如果它是最好的解决方案!
答案 14 :(得分:0)
将数组拆分为两组&lt; = I / 2和&gt; I / 2。然后将它们分成&lt; = I / 4,&gt; I / 4和&lt; = 3I / 4,&gt; 3I / 4 并重复log(I)步骤并检查从外部连接的对,例如1I / 8&lt; =和&gt; 7I / 8,如果它们都包含至少一个元素,则它们加到I. 对于I,这将采用n.Log(I)+ n / 2步