Найдите пару элементов из массива, сумма которых равна заданному числу

122

Дан массив из n целых чисел и задано число X. Найдите все уникальные пары элементов (a, b), сумма которых равна X.

Следующее - мое решение, это O (nLog (n) + n), но я не уверен, оптимально оно или нет.

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
Решение O (n) возможно, если вы поместите все в какой-либо набор O (1) вместо сортировки массива.
Аноним.
1
@Anon Можно поподробнее рассказать, как собрать такой набор?
Gin
3
Используйте хеши. Большинство языков будут иметь амортизированный O (1) HashSet где-нибудь в своих стандартных библиотеках.
Аноним.
15
Незначительная нить - O (nLog (n) + n) - это O (nLog (n)). Обозначение Big O сохраняет только доминирующий член и отбрасывает все члены более низкого порядка.
pjs 01
2
Обратите внимание на оценку короткого замыкания и индивидуальную адресацию: while((arr[i] + arr[j]) <= sum && i < j)должно быть while( i < J && arr[i] + arr[j] <= sum ). (аналогично для второго подцикла)
wildplasser

Ответы:

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
codaddict
источник
26
Вы даже можете сделать это за одну итерацию по массиву, поместив оператор if из второго цикла сразу после присвоения хэша в первом цикле.
Александр Кондрацкий
4
Незначительное примечание: это (а также предложение Александра) будет дважды печатать некоторые пары, независимо от того, определяется ли уникальность пары индексом (как можно понять из этого ответа) или значением (как кажется в OP). Может быть довольно много (O (n ^ 2)) уникальных пар по индексу, например arr=[1,2,1,2,1,2,1,...]. Что касается уникальности по значению, похоже, что другая хеш-таблица с ключом парой значений поможет. По-прежнему хороший, компактный и элегантный ответ. +1
Уильям
2
@codaddict Но что, если массив очень большой? То есть диапазон значений в нем очень большой? Таким образом, хеш-решение будет менее практичным. Какой-нибудь альтернативный и оптимальный метод для того же?
Прашант Сингх,
15
Что делать, если есть дубликаты?
зад
2
Как- hash(K - arr[i]) != iто проверяет и наличие, и отсутствие совпадения? Ожидаю, что там будет отдельная проверка на присутствие.
Джозеф Гарвин
184

Есть 3 подхода к этому решению:

пусть сумма равна T, а n - размер массива.

Подход 1.
Наивный способ сделать это - проверить все комбинации (n выберите 2). Этот исчерпывающий поиск составляет O (n 2 ).

Подход 2: 
 лучший способ - отсортировать массив. Это занимает O (n log n).
Затем для каждого x в массиве A используйте двоичный поиск для поиска Tx. Это займет O (nlogn).
Итак, общий поиск - O (n log n).

Подход 3.
Лучшим способом было бы вставить каждый элемент в хеш-таблицу (без сортировки). Это занимает O (n) как постоянную вставку времени.
Затем для каждого x мы можем просто найти его дополнение Tx, которое равно O (1).
В целом время выполнения этого подхода составляет O (n).


Вы можете сослаться на больше здесь. Спасибо.


kinshuk4
источник
Как бы вы создали хеш-таблицу для элементов массива?
Сатиш Патель
См. Ссылку, которой я поделился. У нас может быть параллельный массив для хранения элемента в качестве индекса, или вы можете добавить элементы в хеш-таблицу и использовать на них contains. Извините за такой поздний ответ.
kinshuk4
11
Вы можете получить ложное срабатывание, если есть элемент, который составляет ровно половину целевой суммы.
Florian F
2
@Florian_F Разве это не частный случай, когда у вас есть ровно половина элемента?
Джозеф Гарвин
1
@jazzz Я имею в виду HashMap, хотя HashSet тоже подойдет. Вот реализация - github.com/kinshuk4/AlgorithmUtil/blob/master/src/com/vaani/… . Надеюсь, поможет.
kinshuk4 06
64

Реализация на Java: использование алгоритма codaddict (возможно, немного отличается)

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

}
}

Для input = {2,45,7,3,5,1,8,9}и если Sum10

Выходные пары:

3,7 
8,2
9,1

Некоторые примечания к решению:

  • Мы повторяем только один раз по массиву -> O (n) раз
  • Время вставки и поиска в Hash равно O (1).
  • Общее время O (n), хотя для хеширования используется дополнительное пространство.
Rambo7
источник
1
Это хорошо ТОЛЬКО если входной массив не имеет дубликатов.
Нарен
2
@Naren: Нет никакой разницы, даже если в данном массиве есть дубликаты
abhishek08aug
1
он не реализует то, что написали codaddicts, и то, что вы сделали, хотя и работает, не является необходимым сложным. Бессмысленно put(k-input[i], input[i])(codaddicts помещает индекс как полезное значение.) То, что вы написали, можно упростить доfor (i:input){ if (intSet.contains(sum-i) { print(i + "," + (sum-i) ); } else {intSet.add(i)}
Адриан Шум
1
Хорошо спасибо. Для справки других людей я просто создал еще одну ветку, чтобы те, кто испытывает трудности с анализом работы этого решения, могли правильно его понять. Вот ссылка: stackoverflow.com/questions/33274952/…
Джон,
2
@ abhishek08aug, это не сработает для {1, 1, 1}
jbakirov
8

Решение в java. Вы можете добавить все элементы String в ArrayList строк и вернуть список. Вот распечатываю.

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

Реализация 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])

Вывод:

1 + 4
2 + 3
ГОРЯЧИЙ
источник
2
загляните
внутрь
4

C ++ 11, сложность времени выполнения 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;
}
iamantony
источник
3

Вот решение, которое учитывает повторяющиеся записи. Он написан на javascript и предполагает, что массив отсортирован. Решение выполняется за время O (n) и не использует дополнительную память, кроме переменной.

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

Я решил это во время интервью для крупной корпорации. Забрали, но не меня. Итак, вот оно для всех.

Начните с обеих сторон массива и медленно продвигайтесь внутрь, не забывая подсчитывать дубликаты, если они существуют.

Он учитывает только пары, но может быть переработан в

  • найти пары
  • найти пары <x
  • найти пары> x

Наслаждайтесь!

Дрон Мозг
источник
Что делают эти строки ?: if(distI > distK) while(_arr[++i]==curI); else while(_arr[--k]==curK);
Юрий Чернышов
В этих строках пропущены повторяющиеся значения с обеих сторон и они считаются парами, если они являются частью пары sum = N
Drone Brain
3

На)

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)

Методология: a + b = c, поэтому вместо поиска (a, b) мы ищем a = c - b

garg10may
источник
Не работает, если у вас есть дубликаты на входе, например: [3, 4, 3, 2, 5] и sum = 6
Антон Данильченко
Исправлены все крайние случаи, теперь попробуйте
garg10май 06
2

Реализация на Java: Использование алгоритма 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]);
        }
    }      

}

}

Вывод:

81, 79
79, 81

Если вам нужны повторяющиеся пары (например: 80,80), просто удалите && (Integer) mapping.get (ka [i])! = I из условия if, и все готово.

Арпит Агарвал
источник
для C # это может работать - 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]) { подсчитывать ++; }}} Console.WriteLine (количество);
MukulSharma
2

Только что посетил этот вопрос на HackerRank, и вот мое решение для цели 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);
}

Надеюсь, это кому-то поможет.

Сару
источник
синтаксис кода понять сложнее, чем сам алгоритм! :)
Rajendra Uppal
1

это реализация O (n * lg n) с использованием реализации двоичного поиска внутри цикла.

#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

В питоне

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

Хорошее решение от Codeaddict. Я взял на себя смелость реализовать его версию на 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

Чтобы разрешить дублирование пар (1,5), (5,1), нам просто нужно удалить && !result[sum-l]инструкцию

obaqueiro
источник
1

Вот код Java для трех подходов:
1. Используя Map O (n), здесь также можно использовать HashSet.
2. Отсортируйте массив, а затем используйте BinarySearch для поиска дополнения O (nLog (n))
3. Традиционный двойной цикл BruteForce 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]+")");
        }
    }
}

}
user1529412
источник
1

Простая программа на java для массивов с уникальными элементами:

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

Простой фрагмент кода Java для печати пар ниже:

    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);
        }
    }
    }
karthikbv
источник
1

Другое решение в Swift: идея состоит в том, чтобы создать хэш, в котором хранятся значения (sum - currentValue), и сравнивать их с текущим значением цикла. Сложность - 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)
Duyen-Хоа
источник
1

Мое решение - Java - без дубликатов

    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("------------------------------");
}
LiozM
источник
0

Это печатает пары и избегает дублирования с помощью побитовых манипуляций.

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]));
            }
        }
    }
}
CodeWarrior
источник
0

Я обошел стороной обработку битов и просто сравнил значения индексов. Это меньше, чем значение итерации цикла (в данном случае i). Это также не будет печатать повторяющиеся пары и повторяющиеся элементы массива.

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);
            }
        }
    }
}
Surya
источник
0

в 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]);
Chrishan
источник
этот ответ был бы более полезным, если бы вы описали порядок роста вашего решения
Томас
0

Одно из решений может быть таким, но не оптимальным (сложность этого кода - 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;
   }
}
Shridutt Kothari
источник
0

Простая версия кода для Python, которая находит нулевую парную сумму и может быть изменена для нахождения 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

Сложность выполнения функции равна O (n) и Space: O (n).

Billz
источник
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

меньше чем o (n) решение будет =>

function(array,k)
          var map = {};
          for element in array
             map(element) = true;
             if(map(k-element)) 
                 return {k,element}
Шишир Арора
источник
Не работает для определенных входов. Плюс от вас требовали вернуть не парижскую сумму
Авиада
0

Решение на Python с использованием понимания списков

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

О (N 2 )

также дает две упорядоченные пары - (a, b) и (b, a), а также

Ашвин Аравинд
источник
Вы можете указать язык, уникальны ли пары (a, b) и (b, a) и на какой вопрос отвечает этот вопрос (вопрос не содержит явного - I am not sure … Thanks for comments). Вы можете обозначить удар по сложности ближе к O (n²).
greybeard
0

Я могу сделать это за O (n). Дай мне знать, когда захочешь получить ответ. Обратите внимание, что он включает в себя простой однократный обход массива без сортировки и т. Д. Я также должен упомянуть, что он использует коммутативность сложения и не использует хеши, но тратит впустую память.


используя Систему; using System.Collections.Generic;

/ * Существует подход O (n) с использованием таблицы поиска. Подход состоит в том, чтобы сохранить значение в «бункере», который можно легко найти (например, O (1)), если оно является кандидатом на соответствующую сумму.

например,

для каждого a [k] в массиве мы просто помещаем его в другой массив в позицию x - a [k].

Предположим, что у нас есть [0, 1, 5, 3, 6, 9, 8, 7] и x = 9

Создаем новый массив,

значение индексов

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

ТОГДА важны только те значения, которые имеют индекс в новой таблице.

Итак, скажем, когда мы достигаем 9 или равного числа, мы видим, имеет ли наш новый массив индекс 9-9 = 0. Поскольку он знает, что все содержащиеся в нем значения прибавятся к 9. (обратите внимание, что в этом случае очевидно, что есть только 1 возможный, но в нем может быть несколько значений индекса, которые нам нужно сохранить).

Таким образом, фактически нам нужно всего лишь один раз пройти через массив. Поскольку сложение коммутативно, мы получим все возможные результаты.

Например, когда мы дойдем до 6, мы получим индекс в нашей новой таблице как 9 - 6 = 3. Поскольку таблица содержит это значение индекса, мы знаем значения.

По сути, это обмен скорости на память. * /

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();
        }
    }
}
AbstractDissonance
источник
В основном, чтобы избежать хешей, мы должны создать таблицу, которая может принимать случайные вставки по несколько произвольным индексам. Поэтому я использую M, чтобы убедиться, что элементов достаточно, и заранее выделяю непрерывный набор, даже если большинство из них не будет использоваться. Хеш-набор позаботится об этом напрямую.
AbstractDissonance
Итак, вы используете хэш-набор с простой хеш-функцией и размером больше максимального значения вашей хеш-функции?
Крис Хопман
Также на этом этапе можно использовать функцию идентификации для вашей хэш-функции. То есть поместите [k] в a [k] -й «мусорный бак».
Крис Хопман
Поскольку a [k] и X - a [k] используются в качестве индексов, а я использую массив, это означает, что минимальный индекс не может быть 0. Следовательно, я просто добавляю очень большое число, чтобы сдвинуть их вверх. Если бы можно было создать хеш-функцию, которая работала бы для произвольных значений, тогда они могли бы использовать простой список без необходимости делать это смещение. Сдвиг + предварительное выделение помогает избежать создания хеша (или это можно представить как очень простой (и быстрый) хеш).
AbstractDissonance
-1

Решение 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);
}
gor181
источник
Очень удобно .... вы используете Stringify (O (n) время и пространство) на каждой итерации ..
Aviad
-1

https://github.com/clockzhong/findSumPairNumber

Я сделал это при стоимости сложности O (m + n) как для времени, так и для объема памяти. Я подозреваю, что это лучший алгоритм на данный момент.

Часы ZHONG
источник
-4

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

var z = (из a в arr из b в arr, где 10 - a == b выберите новый {a, b}). ToList;

Бхавеш Лад
источник