给定一个排序整数数组,我怎样才能找到是否存在一组总和为K的3个元素?

时间:2014-04-07 07:04:27

标签: java arrays algorithm

所以说我有一个排序数组:

{ 1, 2, 3, 4, 5, 6 }

我想知道是否存在三个总和为14的元素。

3 + 5 + 6 = 14

我很确定在O(N)时间内无法做到这一点,但我认为可以用O(N ^ 2)来完成。

4 个答案:

答案 0 :(得分:5)

此问题与3SUM problem类似,可以在O(N^2)中完成。 This java工作代码完成此任务。

    // The function prints the values if there exists 3 distinct indices
    // in the array arr that sum to req.
    void run(){
        int[] arr = { 1, 2, 3, 4, 5, 6 };
        int req = 14;

        // For the algorithm to work correctly, the array must be sorted
        Arrays.sort(arr);      

        for(int i=0; i<arr.length; i++){// Iterate over the elements of the array.

            // Check in linear time whether there exists distinct indices 
            // lo and hi that sum to req-arr[i]
            int lo=0, hi = arr.length-1;
            boolean found = false;
            while(lo<hi){
                if(lo==i){
                    lo++;
                    continue;
                }
                if(hi==i){
                    hi--;
                    continue;
                }
                int val = arr[lo] + arr[hi] + arr[i];
                if(val == req){
                    System.out.println(arr[lo] + " + " + arr[hi] + " + " + arr[i] + " = " + req);
                    found = true;
                    break;
                }else if(val < req){
                    lo++;
                }else{
                    hi--;
                }
            }
            if(found)break;
        }
    }

答案 1 :(得分:2)

在计算理论中,这被称为3sum问题。到目前为止发现的这个问题的最佳解决方案成本为O(N ^ 2)。这是否能以更好的成本解决仍然是一个悬而未决的问题。您可以找到此算法的一个实现here

答案 2 :(得分:0)

这类似于子集总和问题,即NP-Complete  但是将子集长度限制为3,可以找到快速解决方案 您的问题等同于3SUM problem.
您的问题中r = K

伪代码: O(N ^ 2)

for (i in 1..n-2) 
{
  j = i+1  // Start right after i.
  k = n    // Start at the end of the array.

  while (k >= j) {
    // done.
    if (A[i] + A[j] + A[k] == r) return (A[i], A[j], A[k])

    // We didn't match. Let's try to get a little closer:
    //   If the sum was too big, decrement k.
    //   If the sum was too small, increment j.
    (A[i] + A[j] + A[k] > r) ? k-- : j++
  }
  // When the while-loop finishes, j and k have passed each other and there's
  // no more useful combinations that we can try with this i.
}

答案 3 :(得分:0)

如果k与数组的大小(或更小)大致相同且所有数字都是正数(处理零是微不足道的),则可以有效地使用DP。对于从0到k的所有数字,您记得是否可以使用数组中的零个,一个,两个或三个整数来获取它。该解决方案的时间为O(Nk),空间为O(k),并且非常易于实施。

int[] myarray = {1, 2, 3, 4, 5, 6};
int k = 14;

int[] dp = new int[k+1];
dp[0] = 1;
for (int i = 0; i < myarray.length; ++i) {
    for (int j = k; j >= myarray[i]; --j) {
        dp[j] |= dp[j-myarray[i]] << 1;
    }
}
if ((dp[k] & 8) > 0) {
    System.out.println("YES");
} else {
    System.out.println("NO");
}