给定一个数字列表和一个数字k,返回列表中是否存在任意两个数字相加等于k。

35

这个问题是在Google的编程面试中提出的。我想到了两种方法:

  1. 找到所有长度为n的子序列,计算两个元素的和并检查它是否等于k。如果是,则打印Yes,否则继续搜索。这是一种暴力的方法。

  2. 将数组按非递减顺序排序。然后从其右侧开始遍历数组。假设我们有一个已排序的数组{3,5,7,10},我们想让总和为17。我们将从元素10开始,索引=3,用“j”表示索引。然后包括当前元素并计算required_sum = sum-current_element。之后,我们可以在array [0-(j-1)] 中执行二元或三元搜索,以查找其值等于required_sum的元素。如果我们找到这样的元素,那么我们可以停止搜索,因为我们已经找到了一个长度为2且总和为给定总和的子序列。如果我们没有找到这样的元素,则将j的索引减小,并针对长度为length-1的结果子数组(在这种情况下排除索引3处的元素)重复上述步骤。

这里我们考虑到数组可能包含负数和正数整数。

您能推荐比这更好的解决方案吗?也许是DP方案?一个能进一步减少时间复杂度的解决方案。


9
有一个时间复杂度为O(n),空间复杂度也为O(n)的算法。对于每个元素,检查它是否存在于哈希表中。如果不存在,则将k-arr[i]存储起来,并继续下一个元素。 - thebenman
字典和“sum make trick of this question”的含义与程序设计相关。 - RoundTwo
1
数组中的数字可以重复吗? - Vitaliy Yanchuk
1
我所看到的问题版本还包括必须在一次遍历中完成的要求。 - burntsugar
44个回答

2
def sum_total(list, total):

    dict = {}

    for i in lista:
        if (total - i) in dict:
            return True
        else:
            dict[i] = i

    return False

2

Python 代码:

L = list(map(int,input("Enter List: ").split()))
k = int(input("Enter value: "))

for i in L:
    if (k - i) in L:
        print("True",k-i,i)

2

这里是Swift解决方案:

func checkTwoSum(array: [Int], k: Int) -> Bool {
    var foundPair = false
    for n in array {
        if array.contains(k - n) {
            foundPair = true
            break
        } else {
            foundPair = false
        }
    }

    return foundPair
}

1
这里是一个C语言实现,用于排序O(n^2)时间和空间复杂度。为了解决问题,我们使用递归进行单次遍历,时间和空间复杂度均为O(n)。
/* 给定一个数字列表和一个数字k,返回列表中是否存在任意两个数字相加等于k。 例如,给定[10,15,3,7]和k=17,则返回10+7=17。 奖励:能否一次遍历完成? */
#include<stdio.h>
int rec(int i , int j ,int k , int n,int array[])
{
  int sum;
  for( i = 0 ; i<j ;)
  {
      sum = array[i] + array[j];
      if( sum > k)
      {
        j--;
      }else if( sum < k)
      {
        i++;
      }else if( sum == k )
      {
        printf("Value equal to sum of array[%d]  = %d and array[%d] = %d",i,array[i],j,array[j]);
        return 1;//True
      }
  }
  return 0;//False
  }
int main()
  {
  int n ;
  printf("Enter The Value of Number of Arrays = ");
  scanf("%d",&n);
  int array[n],i,j,k,x;
  printf("Enter the Number Which you Want to search in addition of Two Number = ");
  scanf("%d",&x);
  printf("Enter The Value of Array \n");
  for( i = 0 ; i <=n-1;i++)
  {
    printf("Array[%d] = ",i);
    scanf("%d",&array[i]);
  }
  //Sorting of Array
  for( i = 0 ; i <=n-1;i++)
  {
     for( j = 0 ; j <=n-i-1;j++)
     {
     if( array[j]>array[j+1])
     {
       //swapping of two using bitwise operator
       array[j] = array[j]^array[j+1];
       array[j+1] = array[j]^array[j+1];
       array[j] = array[j]^array[j+1];
    }
    }
  }
  k = x ;
  j = n-1;
  rec(i,j,k,n,array);
  return 0 ;
}

输出

Enter The Value of Number of Arrays = 4
Enter the Number Which you Want to search in addition of Two Number = 17
Enter The Value of Array
Array[0] = 10
Array[1] = 15
Array[2] = 3
Array[3] = 7
Value equal to sum of array[1]  = 7 and array[2] = 10
Process returned 0 (0x0)   execution time : 54.206 s
Press any key to continue.

1

我用C++提出了两种解决方案。其中一种是朴素的暴力算法,时间复杂度为O(n^2)。

int main() {
int N,K;
vector<int> list;
cin >> N >> K;
clock_t tStart = clock();   
for(int i = 0;i<N;i++) {
    list.push_back(i+1);
}

for(int i = 0;i<N;i++) {
    for(int j = 0;j<N;j++) {
        if(list[i] + list[j] == K) {
            cout << list[i] << " " << list[j] << endl;
            cout << "YES" << endl;
            printf("Time taken: %.2fs\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);
            return 0;
        }
    }
}
cout << "NO" << endl;

printf("Time taken: %f\n", (double)(clock() - tStart)/CLOCKS_PER_SEC);

return 0;}

这个解决方案需要大量时间来处理较高的输入值,可以想象。
我的第二个解决方案能够在 O(N) 时间内实现。使用一个无序集合,类似于上面的解决方案。
#include <iostream>
#include <unordered_set>
#include <time.h>

using namespace std;

int main() {
    int N,K;
    int trig = 0;
    int a,b;
    time_t tStart = clock();
    unordered_set<int> u;
    cin >> N >> K;
    for(int i =  1;i<=N;i++) {
        if(u.find(abs(K - i)) != u.end()) {
            trig = 1;
            a = i;
            b = abs(K - i);
        }
        u.insert(i);
    }
    trig ? cout << "YES" : cout << "NO";
    cout << endl;
    cout << a << " " << b << endl;
    printf("Time taken %fs\n",(double) (clock() - tStart)/CLOCKS_PER_SEC);
    return 0;
}

快速编辑。为了使第二个示例中的负数正常工作,您只需要删除abs函数即可。 - Jimmy lemieux

1

Python 实现: 使用字典,代码的时间复杂度为 O(n)。我们将 (期望输出 - 当前输入) 存储为字典中的键,然后检查数字是否存在于字典中。在字典中搜索的平均复杂度为 O(1)。

def PairToSumK(numList,requiredSum):
    dictionary={}
    for num in numList:
        if requiredSum-num not in dictionary:
            dictionary[requiredSum-num]=0
        if num in dictionary:
            print(num,requiredSum-num)
            return True
    return False

arr=[10, 5, 3, 7, 3]
print(PairToSumK(arr,6))

这并没有考虑到总和是列表中某个数字的两倍的情况。例如:PairToSumK([1,2],2) 应该是 False,但实际上是 True。 - Ian

1

JavaScript

const findPair = (array, k) => {
  array.sort((a, b) => a - b);
  let left = 0;
  let right = array.length - 1;

  while (left < right) {
    const sum = array[left] + array[right];
    if (sum === k) {
      return true;
    } else if (sum < k) {
      left += 1;
    } else {
      right -= 1;
    }
  }

  return false;
}

感谢您提供的解决方案。看起来很棒! - Pavot

1
使用Java中的HashSet,我们可以一次性完成,或者时间复杂度为O(n)。
import java.util.Arrays;
import java.util.HashSet;

public class One {
    public static void main(String[] args) {
        sumPairsInOne(10, new Integer[]{8, 4, 3, 7});
    }


    public static void sumPairsInOne(int sum, Integer[] nums) {
        HashSet<Integer> set = new HashSet<Integer>(Arrays.asList(nums));

        //adding values to a hash set
        for (Integer num : nums) {
            if (set.contains(sum - num)) {
                System.out.print("Found sum pair => ");
                System.out.println(num + " + " + (sum - num) + " = " + sum);
                return;
            }
        }

        System.out.println("No matching pairs");


    }
}

1
请注意,set.contains在内部具有O(1)的时间复杂度,因此问题的复杂度必须为O(n)。 - java dev

1

这是 Python 代码,时间复杂度为 O(n)。需要在循环时删除当前元素,因为列表可能没有重复数字。

def if_sum_is_k(list, k):
i = 0
list_temp = list.copy()
match = False
for e in list:
    list_temp.pop(i)
    if k - e in list_temp:
        match = True
    i += 1
    list_temp = list.copy()
return match

0

简单的检查(k - arrayValue)不起作用,因为如果 k = 4 并且数组中有一个 2,则会出现误报
因此,您需要从进一步的循环中排除已检查的值
可以使用数组的 pop 函数来完成

php 解决方案:

$answer = function (int $k, array $arr) {
    $inarray = false;
    while (($value = array_pop($arr))) {
        if (in_array(($k - $value), $arr, true)) {
            $inarray = true;
            break;
        }
    }
    return $inarray;
};
var_dump($answer(17, [10, 15, 3, 7]));



Python解决方案:

def ListCheck():
    number = 11
    nums = [10, 15, 3, 7, 9, 6, 4, 8]
    found = 0
    while found == 0:
        if len(nums) < 2: # check if array has at least 2 numbers
            break
        while len(nums) > 1:
            comparenum = nums.pop() # removes comparable number from array to avoid false true if nums has item == number*2 
            if (number - comparenum) in nums:
                print(True)
                found = 1
                break

    if found == 0:
        print(False)
        

ListCheck()
exit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接