web-dev-qa-db-fra.com

Trouver 2 nombres dans un tableau non trié égal à une somme donnée

Nous devons trouver une paire de nombres dans un tableau dont la somme est égale à une valeur donnée.

A = {6,4,5,7,9,1,2}

Sum = 10 Alors les paires sont - {6,4}, {9,1}

J'ai deux solutions pour cela.

  • une solution O(nlogn) - tri + somme de contrôle avec 2 itérateurs (début et fin).
  • an O(n) solution - hachage du tableau. Puis vérification si sum-hash[i] existe ou non dans la table de hachage.

Mais, le problème est que, bien que la deuxième solution soit O(n) temps, mais utilise également O(n) espace).

Donc, je me demandais si nous pouvions le faire dans O (n) temps et O (1) espace. Et ce n'est PAS des devoirs!

49
h4ck3d

Utilisez le tri radix sur place et la première solution OP avec 2 itérateurs, se rapprochant.

Si les nombres dans le tableau ne sont pas une sorte de nombres multi-précision et sont, par exemple, des entiers 32 bits, vous pouvez les trier en 2 * 32 passes en utilisant pratiquement aucun espace supplémentaire (1 bit par passe). Ou 2 * 8 passes et 16 compteurs entiers (4 bits par passe).


Détails pour la solution à 2 itérateurs:

Le premier itérateur pointe initialement vers le premier élément du tableau trié et avance. Le deuxième itérateur pointe initialement vers le dernier élément du tableau et avance vers l'arrière.

Si la somme des éléments référencés par les itérateurs est inférieure à la valeur requise, avancez le premier itérateur. S'il est supérieur à la valeur requise, avancez le deuxième itérateur. S'il est égal à la valeur requise, succès.

Un seul passage est nécessaire, la complexité temporelle est donc O (n). La complexité de l'espace est O (1). Si le tri radix est utilisé, les complexités de l'ensemble de l'algorithme sont les mêmes.


Si vous êtes intéressé par des problèmes connexes (avec une somme de plus de 2 nombres), voir "Sum-subset with a fixed subset size" et "Recherche de trois éléments dans un tableau dont la somme est le plus proche d'un nombre donné " .

19
Evgeny Kluev

Il s'agit d'une question d'entrevue classique de Microsoft Research Asia.
Comment trouver 2 nombres dans un tableau non trié égal à une somme donnée.

[1] solution de force brute
Cet algorithme est très simple. La complexité temporelle est O (N ^ 2)

[2] Utilisation de la recherche binaire
En utilisant la recherche bianry pour trouver le Sum-arr [i] avec chaque arr [i], la complexité temporelle peut être réduite à O (N * logN)

[3] Utilisation de Hash
Sur la base de l'algorithme [2] et de l'utilisation du hachage, la complexité temporelle peut être réduite à O (N), mais cette solution ajoutera l'espace O(N) de hachage).

[4] Algorithme optimal:

Pseduo-code:

for(i=0;j=n-1;i<j)
   if(arr[i]+arr[j]==sum) return (i,j);
else if(arr[i]+arr[j]<sum) i++;
else j--;
return(-1,-1);

ou

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.

Et, cette question est-elle complètement résolue? Non. Si le nombre est N. Ce problème deviendra très complexe.

La quesiton alors:
Comment trouver tous les cas de combinaison avec un numéro donné?

Il s'agit d'un problème classique NP-Complete appelé sous-ensemble-somme.
Pour comprendre NP/NPC/NP-Hard, vous feriez mieux de lire quelques livres professionnels.

Les références:
[1] http://www.quora.com/Mathematics/How-can-I-find-all-the-combination-cases-with-a-given-number
[2] http://en.wikipedia.org/wiki/Subset_sum_problem

6
Changqi Cai
for (int i=0; i < array.size(); i++){
  int value = array[i];
  int diff = sum - value; 
  if (! hashSet.contains(diffvalue)){
      hashSet.put(value,value);
  } else{
       printf(sum = diffvalue + hashSet.get(diffvalue));
  } 
}

--------
Sum being sum of 2 numbers.
3
Sandeep
    public void printPairsOfNumbers(int[] a, int sum){
    //O(n2)
    for (int i = 0; i < a.length; i++) {
        for (int j = i+1; j < a.length; j++) {
            if(sum - a[i] == a[j]){
                //match..
                System.out.println(a[i]+","+a[j]);
            }
        }
    }

    //O(n) time and O(n) space
    Set<Integer> cache = new HashSet<Integer>();
    cache.add(a[0]);
    for (int i = 1; i < a.length; i++) {
        if(cache.contains(sum - a[i])){
            //match//
            System.out.println(a[i]+","+(sum-a[i]));
        }else{
            cache.add(a[i]);
        }
    }

}
1
Amandeep Dhanjal

Si vous supposez que la valeur M à laquelle les paires sont supposées résumer est constante et que les entrées dans le tableau sont positives, vous pouvez le faire en une seule fois (O(n) heure) en utilisant les pointeurs M/2 (O(1) espace) comme suit. Les pointeurs sont étiquetés P1,P2,...,Pkk=floor(M/2). Ensuite, faites quelque chose comme ça

for (int i=0; i<N; ++i) {
  int j = array[i];
  if (j < M/2) {
    if (Pj == 0)
      Pj = -(i+1);   // found smaller unpaired
    else if (Pj > 0)
      print(Pj-1,i); // found a pair
      Pj = 0;
  } else
    if (Pj == 0)
      Pj = (i+1);    // found larger unpaired
    else if (Pj < 0)
      print(Pj-1,i); // found a pair
      Pj = 0;
  }
}

Vous pouvez gérer des entrées répétées (par exemple deux 6) en stockant les index sous forme de chiffres dans la base N, par exemple. Pour M/2, Vous pouvez ajouter le conditionnel

  if (j == M/2) {
    if (Pj == 0)
      Pj = i+1;      // found unpaired middle
    else
      print(Pj-1,i); // found a pair
      Pj = 0;
  } 

Mais maintenant, vous avez le problème de mettre les paires ensemble.

1
PengOne

La solution évidente ne fonctionne-t-elle pas (itération sur chaque paire consécutive) ou les deux nombres sont-ils dans n'importe quel ordre?

Dans ce cas, vous pouvez trier la liste de nombres et utiliser un échantillonnage aléatoire pour partitionner la liste triée jusqu'à ce que vous ayez une sous-liste suffisamment petite pour être itérée.

0
Blender

https://github.com/clockzhong/findSumPairNumber

#! /usr/bin/env python
import sys
import os
import re


#get the number list
numberListStr=raw_input("Please input your number list (seperated by spaces)...\n")
numberList=[int(i) for i in numberListStr.split()]
print 'you have input the following number list:'
print numberList

#get the sum target value
sumTargetStr=raw_input("Please input your target number:\n")
sumTarget=int(sumTargetStr)
print 'your target is: '
print sumTarget


def generatePairsWith2IndexLists(list1, list2):
    result=[]
    for item1 in list1:
        for item2 in list2:
            #result.append([item1, item2])
            result.append([item1+1, item2+1])
    #print result
    return result

def generatePairsWithOneIndexLists(list1):
    result=[]
    index = 0
    while index< (len(list1)-1):
        index2=index+1
        while index2 < len(list1):
            #result.append([list1[index],list1[index2]])
            result.append([list1[index]+1,list1[index2]+1])
            index2+=1
        index+=1
    return result


def getPairs(numList, target):
    pairList=[]
    candidateSlots=[] ##we have (target-1) slots 

    #init the candidateSlots list
    index=0
    while index < target+1:
        candidateSlots.append(None)
        index+=1

    #generate the candidateSlots, contribute O(n) complexity
    index=0
    while index<len(numList):
        if numList[index]<=target and numList[index]>=0:
            #print 'index:',index
            #print 'numList[index]:',numList[index]     
            #print 'len(candidateSlots):',len(candidateSlots)
            if candidateSlots[numList[index]]==None:
                candidateSlots[numList[index]]=[index]
            else:
                candidateSlots[numList[index]].append(index)
        index+=1

    #print candidateSlots

    #generate the pairs list based on the candidateSlots[] we just created
    #contribute O(target) complexity
    index=0
    while index<=(target/2):
        if candidateSlots[index]!=None and candidateSlots[target-index]!=None:
            if index!=(target-index):
                newPairList=generatePairsWith2IndexLists(candidateSlots[index], candidateSlots[target-index])
            else:
                newPairList=generatePairsWithOneIndexLists(candidateSlots[index])
            pairList+=newPairList
        index+=1

    return pairList

print getPairs(numberList, sumTarget)

J'ai réussi à implémenter une solution avec Python sous O (n + m) temps et espace. Le "m" signifie la valeur cible dont la somme de ces deux nombres doit être égale. Je crois c'est le coût le plus bas qui pourrait être obtenu. Erict2k a utilisé itertools.combinations, cela coûtera également des coûts d'espace ou de temps similaires ou supérieurs en comparant mon algorithme.

0
Clock ZHONG

Créez un dictionnaire avec des paires Clé (numéro de la liste) et la valeur est le nombre nécessaire pour obtenir la valeur souhaitée. Ensuite, vérifiez la présence des paires de nombres dans la liste.

def check_sum_in_list(p_list, p_check_sum):
    l_dict = {i: (p_check_sum - i) for i in p_list}
    for key, value in l_dict.items():
        if key in p_list and value in p_list:
            return True
    return False


if __== '__main__':
    l1 = [1, 3, 7, 12, 72, 2, 8]
    l2 = [1, 2, 2, 4, 7, 4, 13, 32]

    print(check_sum_in_list(l1, 10))
    print(check_sum_in_list(l2, 99))

Output:
True
Flase

version 2

import random


def check_sum_in_list(p_list, p_searched_sum):
    print(list(p_list))
    l_dict = {i: p_searched_sum - i for i in set(p_list)}
    for key, value in l_dict.items():
        if key in p_list and value in p_list:
            if p_list.index(key) != p_list.index(value):
                print(key, value)
                return True
    return False


if __== '__main__':
    l1 = []
    for i in range(1, 2000000):
        l1.append(random.randrange(1, 1000))

    j = 0
    i = 9
    while i < len(l1):
        if check_sum_in_list(l1[j:i], 100):
            print('Found')
            break
        else:
            print('Continue searching')
            j = i
            i = i + 10

Output:
...
[154, 596, 758, 924, 797, 379, 731, 278, 992, 167]
Continue searching
[808, 730, 216, 15, 261, 149, 65, 386, 670, 770]
Continue searching
[961, 632, 39, 888, 61, 18, 166, 167, 474, 108]
39 61
Finded
[Finished in 3.9s]
0
Howl Blindfolds

Implémentation de Python 2.7:

import itertools
list = [1, 1, 2, 3, 4, 5,]
uniquelist = set(list)
targetsum = 5
for n in itertools.combinations(uniquelist, 2):
    if n[0] + n[1] == targetsum:
    print str(n[0]) + " + " + str(n[1])

Sortie:

1 + 4
2 + 3
0
Erict2k

Le code suivant retourne vrai si deux entiers dans un tableau correspondent à un entier comparé.

 function compareArraySums(array, compare){

        var candidates = [];

        function compareAdditions(element, index, array){
            if(element <= y){
                candidates.Push(element);
            }
        }

        array.forEach(compareAdditions);

        for(var i = 0; i < candidates.length; i++){
            for(var j = 0; j < candidates.length; j++){
                if (i + j === y){
                    return true;
                }
            }
        }
    }
0
redress

L'itération des deux extrémités ne devrait-elle pas simplement résoudre le problème?

Triez le tableau. Et commencez à comparer des deux côtés.

if((arr[start] + arr[end]) < sum) start++;
if((arr[start] + arr[end]) > sum) end--;
if((arr[start] + arr[end]) = sum) {print arr[start] "," arr[end] ; start++}
if(start > end)  break;

Complexité temporelle O(nlogn)

0
Piyush Shandilya
`package algorithmsDesignAnalysis;

 public class USELESStemp {
 public static void main(String[] args){
    int A[] = {6, 8, 7, 5, 3, 11, 10}; 

    int sum = 12;
    int[] B = new int[A.length];
    int Max =A.length; 

    for(int i=0; i<A.length; i++){
        B[i] = sum - A[i];
        if(B[i] > Max)
            Max = B[i];
        if(A[i] > Max)
            Max = A[i];

        System.out.print(" " + B[i] + "");

    } // O(n) here; 

    System.out.println("\n Max = " + Max);

    int[] Array = new int[Max+1];
    for(int i=0; i<B.length; i++){
        Array[B[i]] = B[i];
    } // O(n) here;

    for(int i=0; i<A.length; i++){  
    if (Array[A[i]] >= 0)
        System.out.println("We got one: " + A[i] +" and " + (sum-A[i]));
    } // O(n) here;

} // end main();

/******
Running time: 3*O(n)
*******/
}
0
todedu

Le code ci-dessous prend le tableau et le nombre N comme somme cible. Tout d'abord, le tableau est trié, puis un nouveau tableau contenant les éléments restants est pris, puis analysé non pas par recherche binaire mais par simple balayage du reste et du tableau simultanément.

public static int solution(int[] a, int N) {

    quickSort(a, 0, a.length-1);    // nlog(n)

    int[] remainders = new int[a.length];

    for (int i=0; i<a.length; i++) {
        remainders[a.length-1-i] = N - a[i];     // n
    }

    int previous = 0;

    for (int j=0; j<a.length; j++) {            // ~~ n

        int k = previous;

        while(k < remainders.length && remainders[k] < a[j]) {
            k++;
        }

        if(k < remainders.length && remainders[k] == a[j]) {
            return 1;
        }

        previous = k;
    }

    return 0;
}
0
user3264350

si c'est un tableau trié et que nous n'avons besoin que d'une paire de nombres et pas de toutes les paires, nous pouvons le faire comme ceci:

public void sums(int a[] , int x){ // A = 1,2,3,9,11,20 x=11
    int i=0 , j=a.length-1;
    while(i < j){
      if(a[i] + a[j] == x) system.out.println("the numbers : "a[x] + " " + a[y]);
      else if(a[i] + a[j] < x) i++;
      else j--;
    }
}

1 2 3 9 11 2 || i = 0, j = 5 somme = 21 x = 11
1 2 3 9 11 20 || i = 0, j = 4 somme = 13 x = 11
1 2 3 9 11 20 || i = 0, j = 4 somme = 11 x = 11
FIN

0
igor
public static ArrayList<Integer> find(int[] A , int target){
    HashSet<Integer> set = new HashSet<Integer>();
    ArrayList<Integer> list = new ArrayList<Integer>();
    int diffrence = 0;
    for(Integer i : A){
        set.add(i);
    }
    for(int i = 0; i <A.length; i++){
        diffrence = target- A[i];
    if(set.contains(diffrence)&&A[i]!=diffrence){
        list.add(A[i]);
        list.add(diffrence);
        return list;
    }
     }
    return null;
}
0
Suraj

Si les nombres ne sont pas très grands, vous pouvez utiliser une transformée de Fourier rapide pour multiplier deux polynômes, puis dans O(1) vérifier si le coefficient avant x ^ (somme nécessaire) la somme est supérieure à zéro. O (n log n) total!

0
alkurmtl

// Java implémentation utilisant Hashing import Java.io. *;

class PairSum {private static final int MAX = 100000; // Taille maximale de Hashmap

static void printpairs(int arr[],int sum)
{
    // Declares and initializes the whole array as false
    boolean[] binmap = new boolean[MAX];

    for (int i=0; i<arr.length; ++i)
    {
        int temp = sum-arr[i];

        // checking for condition
        if (temp>=0 && binmap[temp])
        {
            System.out.println("Pair with given sum " +
                                sum + " is (" + arr[i] +
                                ", "+temp+")");
        }
        binmap[arr[i]] = true;
    }
}

// Main to test the above function
public static void main (String[] args)
{
    int A[] = {1, 4, 45, 6, 10, 8};
    int n = 16;
    printpairs(A,  n);
}

}

0
Sai kiran