Trova una coppia di elementi da un array la cui somma è uguale a un dato numero


122

Dato un array di n numeri interi e dato un numero X, trova tutte le coppie uniche di elementi (a, b), la cui somma è uguale a X.

La seguente è la mia soluzione, è O (nLog (n) + n), ma non sono sicuro che sia ottimale o meno.

int main(void)
{
    int arr [10] = {1,2,3,4,5,6,7,8,9,0};
    findpair(arr, 10, 7);
}
void findpair(int arr[], int len, int sum)
{
    std::sort(arr, arr+len);
    int i = 0;
    int j = len -1;
    while( i < j){
        while((arr[i] + arr[j]) <= sum && i < j)
        {
            if((arr[i] + arr[j]) == sum)
                cout << "(" << arr[i] << "," << arr[j] << ")" << endl;
            i++;
        }
        j--;
        while((arr[i] + arr[j]) >= sum && i < j)
        {
            if((arr[i] + arr[j]) == sum)
                cout << "(" << arr[i] << "," << arr[j] << ")" << endl;
            j--;
        }
    }
}

3
Una soluzione O (n) è possibile se metti tutto in un insieme O (1) di qualche tipo invece di ordinare l'array.
Anon.

1
@Anon Puoi dirci più dettagli, come costruire un set del genere?
Gin

3
Usa gli hash. La maggior parte delle lingue avrà un HashSet O (1) ammortizzato da qualche parte nelle loro librerie standard.
Anon.

15
Un pignolo minore - O (nLog (n) + n) è O (nLog (n)). La notazione O grande conserva solo il termine dominante e elimina tutti i termini di ordine inferiore.
pjs

2
Nota la valutazione del cortocircuito e l'indirizzamento off-by-one: while((arr[i] + arr[j]) <= sum && i < j)dovrebbe essere while( i < J && arr[i] + arr[j] <= sum ). (simile per il secondo subloop)
wildplasser

Risposte:


135
# Let arr be the given array.
# And K be the give sum


for i=0 to arr.length - 1 do
  hash(arr[i]) = i  // key is the element and value is its index.
end-for

for i=0 to arr.length - 1 do
  if hash(K - arr[i]) != i  // if Kth element exists and it's different then we found a pair
    print "pair i , hash(K - arr[i]) has sum K"
  end-if
end-for

26
Potresti anche farlo in una iterazione attraverso l'array, inserendo la tua istruzione if dal secondo ciclo, subito dopo l'assegnazione hash nel primo ciclo.
Alexander Kondratskiy

4
Nota minore: questo (così come il suggerimento di Alexander) stamperà due volte alcune coppie, se l'unicità di una coppia è determinata dall'indice (come potrebbe essere implicito da questa risposta) o dal valore (come sembra nell'OP). Potrebbero esserci parecchie (O (n ^ 2)) coppie uniche per indice, ad es arr=[1,2,1,2,1,2,1,...]. Per unicità in base al valore, sembra che un'altra tabella hash con chiave da una coppia di valori farebbe il trucco. Ancora una bella, compatta, elegante risposta. +1
William

2
@codaddict Ma cosa succede se l'array è molto grande? Voglio dire che l'intervallo di valori in esso è molto ampio? Quindi, la soluzione hash sarà meno pratica allora. Qualche metodo alternativo e ottimale per lo stesso?
Prashant Singh

15
E se ci sono duplicati?
Zad

2
In hash(K - arr[i]) != iqualche modo controlla sia la presenza che la mancanza di una corrispondenza? Mi aspetto che ci sia un controllo separato per la presenza.
Joseph Garvin

185

Esistono 3 approcci a questa soluzione:

Sia T e n la dimensione dell'array

Approccio 1:
il modo ingenuo per farlo sarebbe controllare tutte le combinazioni (n scegli 2). Questa ricerca esaustiva è O (n 2 ).

Approccio 2: 
 un modo migliore sarebbe ordinare l'array. Questo richiede O (n log n)
Quindi per ogni x nell'array A, usa la ricerca binaria per cercare Tx. Questo richiederà O (nlogn).
Quindi, la ricerca complessiva è O (n log n)

Approccio 3:
il modo migliore sarebbe inserire ogni elemento in una tabella hash (senza ordinare). Questo prende O (n) come inserimento a tempo costante.
Quindi per ogni x, possiamo solo cercare il suo complemento, Tx, che è O (1).
Nel complesso il tempo di esecuzione di questo approccio è O (n).


Puoi fare riferimento di più qui . Grazie.



Come creeresti una tabella hash per gli elementi dell'array?
Satish Patel

Fare riferimento al collegamento che ho condiviso. Possiamo avere un array parallelo per memorizzare l'elemento come indice, oppure puoi aggiungere gli elementi alla tabella hash e usare contiene su di essi. Ci scusiamo per una risposta così tardiva.
kinshuk4

11
Potresti ottenere un falso positivo se c'è un elemento che è esattamente la metà della somma target.
Florian F

2
@Florian_F Non puoi solo un caso speciale in cui hai un elemento che è esattamente la metà?
Joseph Garvin

1
@jazzz Intendo HashMap qui, anche se HashSet lo farà. Ecco l'implementazione: github.com/kinshuk4/AlgorithmUtil/blob/master/src/com/vaani/… . Spero che sia d'aiuto.
kinshuk4

64

Implementazione in Java: utilizzo dell'algoritmo di codaddict (forse leggermente diverso)

import java.util.HashMap;

public class ArrayPairSum {


public static void main(String[] args) {        

    int []a = {2,45,7,3,5,1,8,9};
    printSumPairs(a,10);        

}


public static void printSumPairs(int []input, int k){
    Map<Integer, Integer> pairs = new HashMap<Integer, Integer>();

    for(int i=0;i<input.length;i++){

        if(pairs.containsKey(input[i]))
            System.out.println(input[i] +", "+ pairs.get(input[i]));
        else
            pairs.put(k-input[i], input[i]);
    }

}
}

Per input = {2,45,7,3,5,1,8,9}e se Sum è10

Coppie di uscite:

3,7 
8,2
9,1

Alcune note sulla soluzione:

  • Si itera solo una volta attraverso l'array -> O (n) time
  • Il tempo di inserimento e ricerca in Hash è O (1).
  • Il tempo complessivo è O (n), sebbene utilizzi spazio aggiuntivo in termini di hash.

1
Questo è valido SOLO se la matrice di input non ha duplicati.
Naren

2
@Naren: Non fa differenza anche se ci sono duplicati nell'array dato
abhishek08aug

1
non implementa ciò che ha scritto codaddicts e ciò che hai fatto, sebbene funzioni, non è complicato. Non ha senso put(k-input[i], input[i])(codaddicts mette l'indice come valore utile.) Ciò che hai scritto può essere semplificato infor (i:input){ if (intSet.contains(sum-i) { print(i + "," + (sum-i) ); } else {intSet.add(i)}
Adrian Shum,

1
Va bene, grazie. Per scopi di riferimento di altre persone, ho appena creato un altro thread in modo che chi ha difficoltà ad analizzare come funziona questa soluzione possa capirlo correttamente. Ecco il link: stackoverflow.com/questions/33274952/…
John

2
@ abhishek08aug questo non funzionerà per {1, 1, 1}
jbakirov

8

Soluzione in java. È possibile aggiungere tutti gli elementi String a un ArrayList di stringhe e restituire l'elenco. Qui lo sto solo stampando.

void numberPairsForSum(int[] array, int sum) {
    HashSet<Integer> set = new HashSet<Integer>();
    for (int num : array) {
        if (set.contains(sum - num)) {
            String s = num + ", " + (sum - num) + " add up to " + sum;
            System.out.println(s);
        }
        set.add(num);
    }
}

4

Implementazione di Python:

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])

Produzione:

1 + 4
2 + 3

2
guarda dentro ... sarà un sovraccarico per cercare l'elemento
Nikhil Rupanawar

4

C ++ 11, complessità del tempo di esecuzione O (n):

#include <vector>
#include <unordered_map>
#include <utility>

std::vector<std::pair<int, int>> FindPairsForSum(
        const std::vector<int>& data, const int& sum)
{
    std::unordered_map<int, size_t> umap;
    std::vector<std::pair<int, int>> result;
    for (size_t i = 0; i < data.size(); ++i)
    {
        if (0 < umap.count(sum - data[i]))
        {
            size_t j = umap[sum - data[i]];
            result.push_back({data[i], data[j]});
        }
        else
        {
            umap[data[i]] = i;
        }
    }

    return result;
}

3

Ecco una soluzione che tiene conto delle voci duplicate. È scritto in javascript e presuppone che l'array sia ordinato. La soluzione viene eseguita in tempo O (n) e non utilizza memoria aggiuntiva a parte la variabile.

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

L'ho risolto durante un colloquio per una grande azienda. L'hanno preso ma non io. Quindi eccolo qui per tutti.

Inizia su entrambi i lati dell'array e procedi lentamente verso l'interno assicurandoti di contare i duplicati se esistono.

Conta solo le coppie ma può essere rielaborato

  • trova le coppie
  • trova le coppie <x
  • trova coppie> x

Godere!


Cosa fanno queste righe ?: if(distI > distK) while(_arr[++i]==curI); else while(_arr[--k]==curK);
Yuriy Chernyshov

Queste righe saltano i valori duplicati da entrambi i lati e le contano come coppie se fanno parte di una somma di coppie = N
Drone Brain

3

Sopra)

def find_pairs(L,sum):
    s = set(L)
    edgeCase = sum/2
    if L.count(edgeCase) ==2:
        print edgeCase, edgeCase
    s.remove(edgeCase)      
    for i in s:
        diff = sum-i
        if diff in s: 
            print i, diff


L = [2,45,7,3,5,1,8,9]
sum = 10          
find_pairs(L,sum)

Metodologia: a + b = c, quindi invece di cercare (a, b) cerchiamo a = c - b


Non funziona se hai duplicati nell'input, come questo: [3, 4, 3, 2, 5] e somma = 6
Anton Danilchenko

Corretti tutti i casi limite, ora prova
garg10 potrebbe il

2

Implementazione in Java: utilizzo dell'algoritmo di codaddict:

import java.util.Hashtable;
public class Range {

public static void main(String[] args) {
    // TODO Auto-generated method stub
    Hashtable mapping = new Hashtable();
    int a[]= {80,79,82,81,84,83,85};
    int k = 160;

    for (int i=0; i < a.length; i++){
        mapping.put(a[i], i);
    }

    for (int i=0; i < a.length; i++){
        if (mapping.containsKey(k - a[i]) && (Integer)mapping.get(k-a[i]) != i){
            System.out.println(k-a[i]+", "+ a[i]);
        }
    }      

}

}

Produzione:

81, 79
79, 81

Se vuoi anche coppie duplicate (ad esempio: 80,80), rimuovi && (Integer) mapping.get (ka [i])! = I dalla condizione if e sei a posto.


per C # questo può essere un lavoro - int k = 16; int count = 0; int [] intArray = {5, 7, 11, 23,8,9,15,1,10,6}; for (int i = 0; i <intArray.Length; i ++) {for (int j = i; j <intArray.Length; j ++) {if ((k - intArray [i]) == intArray [j]) { contare ++; }}} Console.WriteLine (count);
MukulSharma

2

Ho appena risposto a questa domanda su HackerRank ed ecco la mia soluzione "Obiettivo C" :

-(NSNumber*)sum:(NSArray*) a andK:(NSNumber*)k {
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    long long count = 0;
    for(long i=0;i<a.count;i++){

        if(dict[a[i]]) {
            count++;
            NSLog(@"a[i]: %@, dict[array[i]]: %@", a[i], dict[a[i]]);
        }
        else{
            NSNumber *calcNum = @(k.longLongValue-((NSNumber*)a[i]).longLongValue);
            dict[calcNum] = a[i];
        }

    }
    return @(count);
}

Spero che aiuti qualcuno.


la sintassi del codice è difficile da capire rispetto all'algoritmo stesso! :)
Rajendra Uppal

1

questa è l'implementazione di O (n * lg n) usando l'implementazione della ricerca binaria all'interno di un ciclo.

#include <iostream>

using namespace std;

bool *inMemory;


int pairSum(int arr[], int n, int k)
{
    int count = 0;

    if(n==0)
        return count;
    for (int i = 0; i < n; ++i)
    {
        int start = 0;
        int end = n-1;      
        while(start <= end)
        {
            int mid = start + (end-start)/2;
            if(i == mid)
                break;
            else if((arr[i] + arr[mid]) == k && !inMemory[i] && !inMemory[mid])
            {
                count++;
                inMemory[i] = true;
                inMemory[mid] = true;
            }
            else if(arr[i] + arr[mid] >= k)
            {
                end = mid-1;
            }
            else
                start = mid+1;
        }
    }
    return count;
}


int main()
{
    int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    inMemory = new bool[10];
    for (int i = 0; i < 10; ++i)
    {
        inMemory[i] = false;
    }
    cout << pairSum(arr, 10, 11) << endl;
    return 0;
}

1

In pitone

arr = [1, 2, 4, 6, 10]
diff_hash = {}
expected_sum = 3
for i in arr:
    if diff_hash.has_key(i):
        print i, diff_hash[i]
    key = expected_sum - i
    diff_hash[key] = i

1

Bella soluzione da Codeaddict. Mi sono preso la libertà di implementarne una versione in Ruby:

def find_sum(arr,sum)
 result ={}
 h = Hash[arr.map {|i| [i,i]}]
 arr.each { |l| result[l] = sum-l  if h[sum-l] && !result[sum-l]  }
 result
end

Per consentire coppie duplicate (1,5), (5,1) dobbiamo solo rimuovere l' && !result[sum-l]istruzione


1

Ecco il codice Java per tre approcci:
1. Utilizzando Map O (n), anche HashSet può essere utilizzato qui.
2. Ordina l'array e poi usa BinarySearch per cercare il complemento O (nLog (n))
3. BruteForce tradizionale a due cicli O (n ^ 2)

public class PairsEqualToSum {

public static void main(String[] args) {
    int a[] = {1,10,5,8,2,12,6,4};
    findPairs1(a,10);
    findPairs2(a,10);
    findPairs3(a,10);

}


//Method1 - O(N) use a Map to insert values as keys & check for number's complement in map
    static void findPairs1(int[]a, int sum){
        Map<Integer, Integer> pairs = new HashMap<Integer, Integer>();
        for(int i=0; i<a.length; i++){
            if(pairs.containsKey(sum-a[i]))
                System.out.println("("+a[i]+","+(sum-a[i])+")");
            else
               pairs.put(a[i], 0);
        }
    }



//Method2 - O(nlog(n)) using Sort
static void findPairs2(int[]a, int sum){
        Arrays.sort(a);
        for(int i=0; i<a.length/2; i++){
            int complement = sum - a[i];
            int foundAtIndex = Arrays.binarySearch(a,complement);
            if(foundAtIndex >0 && foundAtIndex != i) //to avoid situation where binarySearch would find the original and not the complement like "5"
                System.out.println("("+a[i]+","+(sum-a[i])+")");
        }
 }

//Method 3 - Brute Force O(n^2)
static void findPairs3(int[]a, int sum){

    for(int i=0; i<a.length; i++){
        for(int j=i; j<a.length;j++){
            if(a[i]+a[j] == sum)
                System.out.println("("+a[i]+","+a[j]+")");
        }
    }
}

}

1

Un semplice programma in java per array con elementi unici:

import java.util.*;
public class ArrayPairSum {
    public static void main(String[] args) { 
        int []a = {2,4,7,3,5,1,8,9,5};
        sumPairs(a,10);  
    }

    public static void sumPairs(int []input, int k){
      Set<Integer> set = new HashSet<Integer>();    
      for(int i=0;i<input.length;i++){

        if(set.contains(input[i]))
            System.out.println(input[i] +", "+(k-input[i]));
        else
            set.add(k-input[i]);
       }
    }
}

1

Un semplice snippet di codice Java per stampare le coppie di seguito:

    public static void count_all_pairs_with_given_sum(int arr[], int S){
        if(arr.length < 2){
        return;
    }        
    HashSet values = new HashSet(arr.length);
    for(int value : arr)values.add(value);
    for(int value : arr){
        int difference = S - value;
    if(values.contains(difference) && value<difference){
        System.out.printf("(%d, %d) %n", value, difference);
        }
    }
    }

1

Un'altra soluzione in Swift: l'idea è di creare un hash che memorizzi i valori di (sum - currentValue) e confrontarli con il valore corrente del ciclo. La complessità è O (n).

func findPair(list: [Int], _ sum: Int) -> [(Int, Int)]? {
    var hash = Set<Int>() //save list of value of sum - item.
    var dictCount = [Int: Int]() //to avoid the case A*2 = sum where we have only one A in the array
    var foundKeys  = Set<Int>() //to avoid duplicated pair in the result.

    var result = [(Int, Int)]() //this is for the result.
    for item in list {

        //keep track of count of each element to avoid problem: [2, 3, 5], 10 -> result = (5,5)
        if (!dictCount.keys.contains(item)) {
            dictCount[item] = 1
        } else {
            dictCount[item] = dictCount[item]! + 1
        }

        //if my hash does not contain the (sum - item) value -> insert to hash.
        if !hash.contains(sum-item) {
            hash.insert(sum-item)
        }

        //check if current item is the same as another hash value or not, if yes, return the tuple.
        if hash.contains(item) &&
            (dictCount[item] > 1 || sum != item*2) // check if we have item*2 = sum or not.
        {
            if !foundKeys.contains(item) && !foundKeys.contains(sum-item) {
                foundKeys.insert(item) //add to found items in order to not to add duplicated pair.
                result.append((item, sum-item))
            }
        }
    }
    return result
}

//test:
let a = findPair([2,3,5,4,1,7,6,8,9,5,3,3,3,3,3,3,3,3,3], 14) //will return (8,6) and (9,5)

1

La mia soluzione - Java - Senza duplicati

    public static void printAllPairSum(int[] a, int x){
    System.out.printf("printAllPairSum(%s,%d)\n", Arrays.toString(a),x);
    if(a==null||a.length==0){
        return;
    }
    int length = a.length;
    Map<Integer,Integer> reverseMapOfArray = new HashMap<>(length,1.0f);
    for (int i = 0; i < length; i++) {
        reverseMapOfArray.put(a[i], i);
    }

    for (int i = 0; i < length; i++) {
        Integer j = reverseMapOfArray.get(x - a[i]);
        if(j!=null && i<j){
            System.out.printf("a[%d] + a[%d] = %d + %d = %d\n",i,j,a[i],a[j],x);
        }
    }
    System.out.println("------------------------------");
}

0

Questo stampa le coppie ed evita i duplicati usando la manipolazione bit per bit.

public static void findSumHashMap(int[] arr, int key) {
    Map<Integer, Integer> valMap = new HashMap<Integer, Integer>();
    for(int i=0;i<arr.length;i++)
        valMap.put(arr[i], i);

    int indicesVisited = 0; 
    for(int i=0;i<arr.length;i++) {
        if(valMap.containsKey(key - arr[i]) && valMap.get(key - arr[i]) != i) {
            if(!((indicesVisited & ((1<<i) | (1<<valMap.get(key - arr[i])))) > 0)) {
                int diff = key-arr[i];
                System.out.println(arr[i] + " " +diff);
                indicesVisited = indicesVisited | (1<<i) | (1<<valMap.get(key - arr[i]));
            }
        }
    }
}

0

Ho ignorato la manipolazione dei bit e ho appena confrontato i valori dell'indice. Questo è inferiore al valore di iterazione del ciclo (i in questo caso). Ciò non stamperà anche le coppie duplicate e gli elementi dell'array duplicati.

public static void findSumHashMap(int[] arr, int key) {
    Map<Integer, Integer> valMap = new HashMap<Integer, Integer>();
    for (int i = 0; i < arr.length; i++) {
        valMap.put(arr[i], i);
    }
    for (int i = 0; i < arr.length; i++) {
        if (valMap.containsKey(key - arr[i])
                && valMap.get(key - arr[i]) != i) {
            if (valMap.get(key - arr[i]) < i) {
                int diff = key - arr[i];
                System.out.println(arr[i] + " " + diff);
            }
        }
    }
}

0

in C #:

        int[] array = new int[] { 1, 5, 7, 2, 9, 8, 4, 3, 6 }; // given array
        int sum = 10; // given sum
        for (int i = 0; i <= array.Count() - 1; i++)
            if (array.Contains(sum - array[i]))
                Console.WriteLine("{0}, {1}", array[i], sum - array[i]);

questa risposta sarebbe più utile se descrivi l'ordine di crescita della tua soluzione
Thomas

0

Una soluzione può essere questa, ma non ottimale (la complessità di questo codice è O (n ^ 2)):

public class FindPairsEqualToSum {

private static int inputSum = 0;

public static List<String> findPairsForSum(int[] inputArray, int sum) {
    List<String> list = new ArrayList<String>();
    List<Integer> inputList = new ArrayList<Integer>();
    for (int i : inputArray) {
        inputList.add(i);
    }
    for (int i : inputArray) {
        int tempInt = sum - i;
        if (inputList.contains(tempInt)) {
            String pair = String.valueOf(i + ", " + tempInt);
            list.add(pair);
        }
    }
    return list;
   }
}

0

Una semplice versione python del codice che trova una somma di coppie pari a zero e può essere modificata per trovare k:

def sumToK(lst):
    k = 0  # <- define the k here
    d = {} # build a dictionary 

# build the hashmap key = val of lst, value = i
for index, val in enumerate(lst):
    d[val] = index

# find the key; if a key is in the dict, and not the same index as the current key
for i, val in enumerate(lst):
    if (k-val) in d and d[k-val] != i:
        return True

return False

La complessità del tempo di esecuzione della funzione è O (n) e anche Spazio: O (n).


0
 public static int[] f (final int[] nums, int target) {
    int[] r = new int[2];
    r[0] = -1;
    r[1] = -1;
    int[] vIndex = new int[0Xfff];
    for (int i = 0; i < nums.length; i++) {
        int delta = 0Xff;
        int gapIndex = target - nums[i] + delta;
        if (vIndex[gapIndex] != 0) {
            r[0] = vIndex[gapIndex];
            r[1] = i + 1;
            return r;
        } else {
            vIndex[nums[i] + delta] = i + 1;
        }
    }
    return r;
}

0

minore di o (n) soluzione sarà =>

function(array,k)
          var map = {};
          for element in array
             map(element) = true;
             if(map(k-element)) 
                 return {k,element}

Fallirà per determinati input. Inoltre ti veniva richiesto di restituire una somma non parigi
Aviad

0

Soluzione in Python che utilizza la comprensione delle liste

f= [[i,j] for i in list for j in list if j+i==X];

O (N 2 )

fornisce anche due coppie ordinate: (a, b) e (b, a)


Potresti menzionare una lingua, se le coppie (a, b) e (b, a) sono uniche e a quale domanda risponde questa (la domanda non ne contiene una esplicita - I am not sure … Thanks for comments). Potresti indicare la fitta di complessità più vicina a O (n²).
barba grigia

0

Posso farlo in O (n). Fammi sapere quando vuoi la risposta. Nota che implica semplicemente attraversare l'array una volta senza ordinamento, ecc ... Devo anche menzionare che sfrutta la commutatività dell'aggiunta e non usa hash ma spreca memoria.


using System; using System.Collections.Generic;

/ * Esiste un approccio O (n) utilizzando una tabella di ricerca. L'approccio consiste nel memorizzare il valore in un "contenitore" che può essere facilmente consultato (ad esempio, O (1)) se è un candidato per una somma appropriata.

per esempio,

per ogni a [k] nell'array mettiamo semplicemente it in un altro array nella posizione x - a [k].

Supponiamo di avere [0, 1, 5, 3, 6, 9, 8, 7] e x = 9

Creiamo un nuovo array,

valore degli indici

9 - 0 = 9     0
9 - 1 = 8     1
9 - 5 = 4     5
9 - 3 = 6     3
9 - 6 = 3     6
9 - 9 = 0     9
9 - 8 = 1     8
9 - 7 = 2     7

ALLORA gli unici valori che contano sono quelli che hanno un indice nella nuova tabella.

Quindi, diciamo che quando raggiungiamo 9 o uguale vediamo se il nostro nuovo array ha l'indice 9 - 9 = 0. Dato che lo fa sappiamo che tutti i valori che contiene si aggiungeranno a 9. (nota in questo perché è ovvio che c'è solo 1 possibile ma potrebbe contenere più valori di indice che dobbiamo memorizzare).

Quindi, ciò che finiamo per fare è dover muoverci solo una volta attraverso l'array. Poiché l'aggiunta è commutativa, ci ritroveremo con tutti i risultati possibili.

Ad esempio, quando arriviamo a 6, inseriamo l'indice nella nostra nuova tabella come 9 - 6 = 3. Poiché la tabella contiene quel valore di indice, conosciamo i valori.

Questo è essenzialmente uno scambio di velocità con la memoria. * /

namespace sum
{
    class Program
    {
        static void Main(string[] args)
        {
            int num = 25;
            int X = 10;
            var arr = new List<int>();
            for(int i = 0; i <= num; i++) arr.Add((new Random((int)(DateTime.Now.Ticks + i*num))).Next(0, num*2));
            Console.Write("["); for (int i = 0; i < num - 1; i++) Console.Write(arr[i] + ", "); Console.WriteLine(arr[arr.Count-1] + "] - " + X);
            var arrbrute = new List<Tuple<int,int>>();
            var arrfast = new List<Tuple<int,int>>();

            for(int i = 0; i < num; i++)
            for(int j = i+1; j < num; j++)
                if (arr[i] + arr[j] == X) 
                    arrbrute.Add(new Tuple<int, int>(arr[i], arr[j]));




            int M = 500;
            var lookup = new List<List<int>>();
            for(int i = 0; i < 1000; i++) lookup.Add(new List<int>());
            for(int i = 0; i < num; i++)        
            {
                // Check and see if we have any "matches"
                if (lookup[M + X - arr[i]].Count != 0)
                {
                    foreach(var j in lookup[M + X - arr[i]])
                    arrfast.Add(new Tuple<int, int>(arr[i], arr[j])); 
                }

                lookup[M + arr[i]].Add(i);

            }

            for(int i = 0; i < arrbrute.Count; i++)
                Console.WriteLine(arrbrute[i].Item1 + " + " + arrbrute[i].Item2 + " = " + X);
            Console.WriteLine("---------");
            for(int i = 0; i < arrfast.Count; i++)
                Console.WriteLine(arrfast[i].Item1 + " + " + arrfast[i].Item2 + " = " + X);

            Console.ReadKey();
        }
    }
}

Fondamentalmente per evitare hash dobbiamo creare una tabella che possa accettare inserimenti casuali in indici un po 'arbitrari. Quindi uso M per assicurarmi che ci siano abbastanza elementi e pre-allocare un insieme contiguo anche se la maggior parte non verrà usata. Un set di hash si occuperebbe direttamente di questo.
AbstractDissonance

Quindi, stai usando un set di hash con una semplice funzione hash e una dimensione maggiore del valore massimo della tua funzione hash?
Chris Hopman

A questo punto, puoi anche utilizzare la funzione di identità per la tua funzione hash. Cioè, metti un [k] al a [k] -esimo "contenitore".
Chris Hopman

Poiché a [k] e X - a [k] sono usati come indici e sto usando un array, significa che l'indice minimo non può essere 0. Quindi aggiungo semplicemente un numero molto grande per spostarli verso l'alto. Se si potesse creare una funzione hash che funzionasse per valori arbitrari, si potrebbe utilizzare un semplice elenco senza dover eseguire questo spostamento. Lo shifting + preallocation aiuta a evitare di dover creare un hash (o si potrebbe pensare ad un hash molto semplice (e veloce)).
AbstractDissonance

-1

Soluzione Javascript:

var sample_input = [0, 1, 100, 99, 0, 10, 90, 30, 55, 33, 55, 75, 50, 51, 49, 50, 51, 49, 51];
var result = getNumbersOf(100, sample_input, true, []);

function getNumbersOf(targetNum, numbers, unique, res) {
    var number = numbers.shift();

    if (!numbers.length) {
        return res;
    }

    for (var i = 0; i < numbers.length; i++) {
        if ((number + numbers[i]) === targetNum) {
            var result = [number, numbers[i]];
            if (unique) {
              if (JSON.stringify(res).indexOf(JSON.stringify(result)) < 0) {
                res.push(result);                
              }
            } else {
              res.push(result);
            }
            numbers.splice(numbers.indexOf(numbers[i]), 1);
            break;
        }
    }
    return getNumbersOf(targetNum, numbers, unique, res);
}

Molto efficiente .... stai usando Stringify (O (n) time and space) ogni iterazione ..
Aviad


-4

int [] arr = {1,2,3,4,5,6,7,8,9,0};

var z = (da a in arr da b in arr dove 10 - a == b seleziona nuovo {a, b}). ToList;

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.