给定一个数字列表和一个数字 k,返回列表中的任意两个数字加起来是不是为 k

Posted

技术标签:

【中文标题】给定一个数字列表和一个数字 k,返回列表中的任意两个数字加起来是不是为 k【英文标题】:Given a list of numbers and a number k, return whether any two numbers from the list add up to k给定一个数字列表和一个数字 k,返回列表中的任意两个数字加起来是否为 k 【发布时间】:2018-12-20 08:57:24 【问题描述】:

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

    查找长度的所有子序列。这样做时计算两个元素的和并检查它是否等于 k。如果是,打印是,否则继续搜索。这是一种蛮力方法。

    按非降序对数组进行排序。然后从右端开始遍历数组。假设我们有排序数组 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解决方案可能吗?一种可以进一步降低时间复杂度的解决方案。

【问题讨论】:

对此有一个O(n) 时空算法。对于每个元素,检查它是否存在于 hashmap 中。如果没有,' 存储 k - arr[i] 并移动到下一个元素。 字典和 sum 的含义使这个问题变得棘手。 数组中的数字可以重复吗? 我看到的问题的版本中还包括必须1遍完成的要求。 【参考方案1】:

这是一个 Java 实现,其时间复杂度与用于对数组排序的算法相同。请注意,这比您的第二个想法要快,因为我们不需要在每次检查数字时都在整个数组中搜索匹配的伙伴。

public static boolean containsPairWithSum(int[] a, int x) 
    Arrays.sort(a);
    for (int i = 0, j = a.length - 1; i < j;) 
        int sum = a[i] + a[j];
        if (sum < x)
            i++;
        else if (sum > x)
            j--;
        else
            return true;
    
    return false;

归纳证明:a[0,n] 为长度为 n+1 的数组,p = (p1, p2) 其中 p1、p2 为整数,p1 &lt;= p2(w.l.o.g.)。假设a[0,n] 包含 p1 和 p2。如果不是,那么算法显然是正确的。

基本情况(i = 0,j = n): a[0,-1] 不包含 p1,a[n,n+1] 不包含 p2。

假设: a[0,i-1] 不包含 a[i]a[j+1,n] 不包含 p2。

步骤案例(i 到 i + 1 或 j 到 j - 1):

    假设p1 = a[i]。然后,由于p1 + a[j] &lt; p1 + p2,索引 j 必须增加。但是从假设中我们知道a[j+1,n-1] 不包含p2。矛盾。随之而来的是p1 != a[i]。 j 到 j - 1 类似。

因为每次迭代,a[0,i-1]a[j+1,n],不包含 p1,并且 p2a[i,j] 包含 p1p2。最终,a[i] = p1a[j] = p2 算法返回 true。

【讨论】:

简单的解决方案。非常感谢您的回复。谢谢你。 :) 如果问题询问了 n 个元素子序列的总和为 k,您能否提出一种方法? @Jhanak Didwania 但是你的问题没有提到子序列,只有两个数字。 @MBo 如果问题不限于两个数字,那应该是什么方法? 子集和问题。这是完全不同的问题。【参考方案2】:

这是具有 O(n) 时间复杂度和 O(n) 空间的 java 实现。这个想法是有一个 HashMap ,它将包含每个数组元素 w.r.t 目标的补码。如果找到补码,我们就有 2 个数组元素求和为目标。

 public boolean twoSum(int[] nums, int target) 
    if(nums.length == 0 || nums == null) return false;

    Map<Integer, Integer> complementMap = new HashMap<>();

    for (int i = 0; i < nums.length; i++) 
         int curr = nums[i];
         if(complementMap.containsKey(target - curr))
           return true;
         
    complementMap.put(curr, i);
    
  return false;

【讨论】:

非常优雅的解决方案,但补充是什么意思?【参考方案3】:

这个问题可以通过O(N)时间和空间复杂度的set来轻松解决。首先将array的所有元素加入set,然后遍历array的每个元素,检查K-ar[i]是否为是否存在于集合中。

这是复杂度为 O(N) 的 java 代码:

boolean flag=false;
HashSet<Long> hashSet = new HashSet<>();
for(int i=0;i<n;i++)
    if(hashSet.contains(k-ar[i]))flag=true;
    hashSet.add(ar[i]);

if(flag)out.println("YES PRESENT");
else out.println("NOT PRESENT");

【讨论】:

@GiorgosLamprakis 这个解决方案与它完美配合。由于我们要选择具有不同索引的两个元素,因此解决方案将在您提供的情况下返回 false。如果它可能相同,则只有将其添加到 set 的顺序会在比较之前发生变化。 不工作:如果你寻找 sum 20 并且集合包含 10,一旦它返回 true。如果您在旅途中构建集合,它会起作用,但不是使用预先构建的集合。 我的意思是代码有效,但英文描述无效。 Java 代码与描述不符。在检查前一个项目是否配对后添加元素。【参考方案4】:

使用 Scala,一次通过,时间和空间复杂度为 O(n)。

import collection.mutable.HashMap

def addUpToK(arr: Array[Int], k: Int): Option[Int] = 

val arrayHelper = new HashMap[Int,Int]()

def addUpToKHelper( i: Int): Option[Int] = 
  if(i < arr.length)
    if(arrayHelper contains k-arr(i) )
      Some(arr(i))
    else
      arrayHelper += (arr(i) -> (k-arr(i)) )
      addUpToKHelper( i+1)
    

  else
   None
  

addUpToKHelper(0)


addUpToK(Array(10, 15, 3, 7), 17)

【讨论】:

这不是 O(n)。扫描arrayHelper contains 将传递这些值。最坏的情况也是 O(n^2)。【参考方案5】:

这是一个 C 实现用于对 O(n2) 时间和空间复杂度进行排序。用于解决问题我们使用 通过递归实现 O(n) 时间和空间复杂度的单次传递。 /* 给定一个数字列表和一个数字 k,返回天气列表中任意两个数字之和为 k。 例如,给定 [10,15,3,7] 和 k of 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.

【讨论】:

【参考方案6】:

这是python的实现

arr=[3,5,7,10]
k=17
flag=False
hashset = set()
for i in range(0,len(arr)):
    if k-arr[i] in hashset:
      flag=True
    hashset.add(arr[i])
print( flag )

【讨论】:

这个,就像这里的许多答案一样,不会考虑 k/2 == i,导致误报。 问题是查找数组中的 2 个数字是否等于一个数字,您所说的是查找对数 @Saurabh 您的方法中的问题是如果 k=20,那么您的程序将打印 true,因为 20-10 再次是数组中存在的 10,但是即使有数组中只有一个 10,这是一个误报。 您已添加设置来解决此问题【参考方案7】:

只需遍历数组即可找到解决方案。初始化一个哈希集并开始迭代数组。如果在集合中找到数组中的当前元素,则返回 true,否则将此元素的补码 (x - arr[i]) 添加到集合中。如果数组的迭代结束没有返回,则表示不存在这样的对,其和等于x,因此返回false。

  public boolean containsPairWithSum(int[] a, int x) 
    Set<Integer> set = new HashSet<>();
    for (int i = 0; i< a.length; i++) 
        if(set.contains(a[i])) 
            return true;
        set.add(x - a[i]);
    
    return false;
 

【讨论】:

【参考方案8】:

Python 解决方案:

def FindPairs(arr, k):
    for i in range(0, len(arr)):
        if k - arr[i] in arr:
            return True
    return False        
A = [1, 4, 45, 6, 10, 8]
n = 100
print(FindPairs(A, n))

或者

def findpair(list1, k):
    for i in range(0, len(list1)):
        for j in range(0, len(list1)):
            if k == list1[i] + list1[j]:
                return True    
    return False       
nums = [10, 5, 6, 7, 3]
k = 100
print(findpair(nums, k))

【讨论】:

有误报的可能,请参阅@saurabh 的回答评论部分。 解决方案看起来不正确,因为它会将数字与自身相加并返回 true..【参考方案9】:

如果你想找到对数,

pairs = [3,5,7,10]
k = 17
counter = 0

for i in pairs:
    if k - i in pairs:
        counter += 1

print(counter//2)

【讨论】:

您可以通过使用列表解析来改进此逻辑:def pair_count(_list, k): return sum([k - j in _list for i in _list]) // 2,它从True == 1 开始工作,sum() 计算生成器中有多少元素为真。显然,这又回到了最初的问题——用return any(k - j in _list for i in _list)替换return语句,这实际上可能效率更高,因为any在第一次出现True时返回True,这意味着你不一定必须在某些情况下,遍历list_ 的每个元素。【参考方案10】:

C++ 解决方案:

int main()

    int n;
    cin>>n;
    int arr[n];
    for(int i = 0; i < n; i++)
    
        cin>>arr[i];
    
    int k;
    cin>>k;
    int t = false;
    for(int i = 0; i < n-1; i++)
    
        int s = k-arr[i];
        for(int j = i+1; j < n; j++)
        
            if(s==arr[j])
            t=true;
        

           
    if (t)
        cout<<"Thank you C++, very cool";
    
    else
        cout<<"Damn it!";
    
        return 0;

【讨论】:

【参考方案11】:
    function check(arr,k)
    var result = false;
    for (var i=0; i < arr.length; i++)
        for (var j=i+1; j < arr.length; j++)
            result = arr[i] + arr[j] == k;
            console.log(`$arr[i] + $arr[j] = $arr[i] + arr[j]`);      
        if (result)
            break;
        
    
    return result;

javascript

【讨论】:

【参考方案12】:

Python

def add(num, k):
for i in range(len(num)):
    for j in range(len(num)):
        if num[i] + num[j] == k:
            return True
return False

【讨论】:

如果被要求参加面试,您将如何改进您的解决方案:)? 它也会通过将数字添加到自身来返回true。【参考方案13】:

这里是 Python。在)。需要在循环时删除当前元素,因为列表可能没有重复的数字。

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

【讨论】:

【参考方案14】:

我在 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) 时间内实施的第二个解决方案。使用 unordered_set,很像上面的解决方案。

#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 函数。【参考方案15】:

C#解决方案:

bool flag = false;
            var list = new List<int>  10, 15, 3, 4 ;
            Console.WriteLine("Enter K");
            int k = int.Parse(Console.ReadLine());

            foreach (var item in list)
            
                flag = list.Contains(k - item);
                if (flag)
                
                    Console.WriteLine("Result: " + flag);
                    return;
                
            
            Console.WriteLine(flag);

【讨论】:

【参考方案16】:

Javascript 解决方案:

function hasSumK(arr, k) 
    hashMap = ;
    for (let value of arr) 
        if (hashMap[value])  return true; else  hashMap[k - value] = true ;
    
    return false;

【讨论】:

【参考方案17】:

我的 C# 实现:

 bool  isPairPresent(int[] numbers,int value)
 
        for (int i = 0; i < numbers.Length; i++)
        
            for (int j = 0; j < numbers.Length; j++)
            
                if (value - numbers[i] == numbers[j])
                    return true;
            
        
        return false;
 

【讨论】:

【参考方案18】:

Python 实现: 代码将使用字典以 O(n) 复杂度执行。我们将 (desired_output - current_input) 存储为字典中的键。然后我们将检查字典中是否存在该数字。在字典中搜索的平均复杂度为 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。【参考方案19】:

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;

【讨论】:

感谢您的解决方案。看起来很棒!【参考方案20】:

这是一个 javascript 解决方案:

function ProblemOne_Solve()

    const k = 17;
    const values = [10, 15, 3, 8, 2];
    for (i=0; i<values.length; i++) 
        if (values.find((sum) =>  return k-values[i] === sum )) return true;
    
    return false;

【讨论】:

【参考方案21】:

我用 Scala 实现

  def hasSome(xs: List[Int], k: Int): Boolean = 
    def check(xs: List[Int], k: Int, expectedSet: Set[Int]): Boolean = 
      xs match 
        case List() => false
        case head :: _ if expectedSet contains head => true
        case head :: tail => check(tail, k, expectedSet + (k - head))
       
    
    check(xs, k, Set())
  

【讨论】:

【参考方案22】:

我已经尝试过 Go Lang 中的解决方案。但是,它消耗 O(n^2) 时间。

package main

import "fmt"

func twoNosAddUptoK(arr []int, k int) bool
    // O(N^2)
    for i:=0; i<len(arr); i++
        for j:=1; j<len(arr);j++ 
            if arr[i]+arr[j] ==k
                return true
            
        
    
    return false


func main()
    xs := []int10, 15, 3, 7
    fmt.Println(twoNosAddUptoK(xs, 17))

【讨论】:

【参考方案23】:

这里有两个非常快速的 Python 实现(这说明了 [1,2]2 的输入应该返回 false 的情况;换句话说,你不能只加倍一个数字,因为它指定了“任意两个”) .

第一个循环遍历术语列表并将每个术语添加到所有先前看到的术语中,直到达到所需的总和。

def do_they_add(terms, result):
    first_terms = []
    for second_term in terms:
        for first_term in first_terms:
            if second_term + first_term == result:
                return True
        first_terms.append(second_term)
    return False

这个从结果中减去每个术语,直到它达到术语列表中的差异(使用a+b=c -&gt; c-a=b的规则)。根据此答案的第一句话,enumerate 和奇数列表索引的使用是为了排除当前值。

def do_they_add_alt(terms, result):
    for i, term in enumerate(terms):
        diff = result - term
        if diff in [*terms[:i - 1], *terms[i + 1:]]:
            return True
    return False

如果您确实允许向自身添加一个数字,那么第二个实现可以简化为:

def do_they_add_alt(terms, result):
    for term in terms:
        diff = result - term
        if diff in terms:
            return True
    return False

【讨论】:

【参考方案24】:

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)

【讨论】:

【参考方案25】:

javascript 中的解决方案

此函数接受 2 个参数并循环遍历列表的长度,并且在循环内部还有另一个循环,它将一个数字与列表中的其他数字相加并检查其总和是否等于 k ​​

const list = [10, 15, 3, 7];
const k = 17;

function matchSum(list, k)
 for (var i = 0; i < list.length; i++) 
  list.forEach(num => 
   if (num != list[i]) 
    if (list[i] + num == k) 
     console.log(`$num + $list[i] = $k (true)`);
    
   
  )
 


matchSum(list, k);

【讨论】:

嗨,欢迎来到 SO。如果您包含有关代码如何回答问题的说明,您的答案将更加有用。【参考方案26】:

我对日常编码问题的回答

# Python 2.7
def pairSumK (arr, goal):
  return any(map(lambda x: (goal - x) in arr, arr))

arr = [10, 15, 3, 7]
print pairSumK(arr, 17)

【讨论】:

【参考方案27】:

这是 Python 3.7 中的代码,复杂度为 O(N):

            def findsome(arr,k):
                if  len(arr)<2:
                    return False;
                for e in arr:
                    if k>e and (k-e) in arr:
                        return True
                return False

也是 Python 3.7 中具有 O(N^2) 复杂度的最佳案例代码:

            def findsomen2 (arr,k):
                if  len(arr)>1:
                    j=0
                    if arr[j] <k:
                        while j<len(arr):
                            i =0
                            while i < len(arr):
                                if arr[j]+arr[i]==k:
                                    return True
                                i +=1
                            j +=1
                return False

【讨论】:

第一个解决方案根本不是 O(N)!检查未排序数组中元素的存在涉及线性操作,即逐个扫描数组。然后你循环执行。因此复杂度仍然是 O(N^2)【参考方案28】:

Javascript 解决方案

function matchSum(arr, k)
  for( var i=0; i < arr.length; i++ )
    for(var j= i+1; j < arr.length; j++)
       if (arr[i] + arr[j] === k)
        return true;
      
     
    
    return false;
  

【讨论】:

【参考方案29】:

使用vavr 库可以非常简洁地完成:

List<Integer> numbers = List(10, 15, 3, 7);
int k = 17;
boolean twoElementsFromTheListAddUpToK = numbers
                .filter(number -> number < k)
                .crossProduct()
                .map(tuple -> tuple._1 + tuple._2)
                .exists(number -> number == k);

【讨论】:

【参考方案30】:

这里是 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

【讨论】:

以上是关于给定一个数字列表和一个数字 k,返回列表中的任意两个数字加起来是不是为 k的主要内容,如果未能解决你的问题,请参考以下文章

给定一个数字列表,如何创建总和的所有组合并返回这些总和的列表

在数字列表中查找下一个奇数或下一个偶数

给定一个数字列表,找到所有矩阵,使得每列和每行总和为 264

将列表中的数字分成 K 等份

查找具有给定总和的数字列表的所有组合

Python实现对于给定的输入,保证和为 target 的不同组合数