检查2个数组是否与I相加

时间:2011-02-04 07:03:43

标签: algorithm

我看到一个面试问题如下: 给出一个未排序的整数数组A和一个整数I,找出A的任何两个成员是否加起来。

任何线索?

时间复杂度应该更低

15 个答案:

答案 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)

  1. 对数组进行排序
  2. 对于X中的每个元素A,执行I-X的二进制搜索。如果I-X位于A,我们就有解决方案。
  3. 这是O(nlogn)

    如果A包含给定(足够小)范围内的整数,我们可以使用技巧O(n)

    1. 我们有一个数组V。对于X中的每个元素A,我们会增加V[X]
    2. 当我们增加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

  1. 在数组的开头拿一个指针,一个在数组的末尾
  2. 在ptr1和ptr2添加两个元素     array[ptr1] + array[ptr2]
  3. if sum > k then decrement ptr2 else increment ptr1
  4. 重复步骤2和步骤3直到ptr1!= ptr2
  5. 同样的事情在这里详细解释。似乎像亚马逊的采访问题 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来实现它

http://www.dsalgo.com/UnsortedTwoSumToK.php

答案 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;
}

我在一家大公司的采访中解决了这个问题。他们接受了但不是我。 所以这里适合所有人。

从数组的两侧开始,慢慢向内工作,确保重复计算(如果存在)。

它只计算对,但可以重新编写

  • 找到对
  • 找到对&lt; x
  • 查找对&gt; X

享受并且不要忘记如果它是最好的解决方案!

答案 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步