Знайдіть пару елементів з масиву, сума якого дорівнює заданому числу


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 Чи можете ви розповісти детальніше, як побудувати такий набір?
Джин

3
Використовуйте хеші. Більшість мов мають амортизований O (1) HashSet десь у своїх стандартних бібліотеках.
Анон.

15
Незначний ніт - O (nLog (n) + n) - O (nLog (n)). Позначення Big O зберігає лише домінуючий термін і відміняє всі терміни нижчого порядку.
pjs

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

26
Ви навіть можете зробити це за одну ітерацію через масив, поставивши свою операцію if з другого циклу, відразу після призначення хешу в першому циклі.
Олександр Кондрацький

4
Незначна примітка: Це (як і пропозиція Олександра) дозволить подвійно надрукувати деякі пари, незалежно від того, чи унікальність пари визначається за індексом (як це може випливати з цієї відповіді) або за значенням (як це здається в ОП). Можливо, існує досить багато (O (n ^ 2)) унікальних пар за індексом, наприклад arr=[1,2,1,2,1,2,1,...]. Для унікальності за значенням, схоже, що інша хеш-таблиця, введена парою значень, зробила б свою справу. Ще приємна, компактна, елегантна відповідь. +1
Вільям

2
@codaddict Але що робити, якщо масив дуже великий? Я маю на увазі діапазон значень в ньому дуже великий? Тож хеш-рішення тоді буде менш практичним. Будь-який альтернативний і оптимальний метод для того ж?
Прашант Сінгх

15
Що робити, якщо є дублікати?
задня

2
Є чи hash(K - arr[i]) != iяким - то чином перевірити як наявність і відсутність матчу? Я очікую, що буде окремий чек на наявність.
Джозеф Гарвін

185

Існує 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).


Ви можете посилатися більше тут. Дякую.



Як би ви створили хеш-таблицю для елементів масиву?
Satish Patel

Перейдіть за посиланням, яким я поділився. У нас може бути паралельний масив для зберігання елемента як індексу, або ви можете додати елементи до хештету та використовувати містять на них. Вибачте за таку пізню відповідь.
kinshuk4

11
Ви можете отримати хибний позитив, якщо є елемент, який становить рівно половину цільової суми.
Флоріан F

2
@Florian_F Ви не можете просто окремий випадок, коли у вас є елемент, який рівно половина?
Джозеф Гарвін

1
@jazzz Я маю на увазі тут HashMap, хоча HashSet теж зробить. Ось реалізація - github.com/kinshuk4/AlgorithmUtil/blob/master/src/com/vaani/… . Сподіваюся, це допомагає.
kinshuk4

64

Впровадження в Java: використання алгоритму кодидації (можливо, дещо інший)

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

}
}

Для вводу = {2,45,7,3,5,1,8,9}і якщо Сума10

Вихідні пари:

3,7 
8,2
9,1

Деякі зауваження щодо рішення:

  • Ми повторюємо лише один раз через масив -> O (n) час
  • Час вставки та пошуку в Hash - це O (1).
  • Загальний час становить O (n), хоча він використовує додатковий простір з точки зору хешу.

1
Це добре ТІЛЬКИ, якщо вхідний масив не дублює.
Нарен

2
@Naren: Це не має значення, навіть якщо в даному масиві є дублікати
abhishek08aug

1
він не реалізує те, що написали кодидакти, і те, що ви зробили, хоча це працює, є зайвим складним. Безглуздо 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;
}

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
  • знайти пари> х

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


Що роблять ці рядки ?: if(distI > distK) while(_arr[++i]==curI); else while(_arr[--k]==curK);
Юрій Чернишов

Ці рядки пропускають через повторювані значення з обох сторін і рахують їх як пари, якщо вони є частиною пари пар = N
Drone Brain

3

O (n)

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


Якщо у вас є дублікати у введенні, не виходить, як: [3, 4, 3, 2, 5] і сума = 6
Антон Данільченко

Виправлено всі крайові корпуси, тепер спробуйте
garg10may

2

Реалізація в Java: Використання алгоритму кодидації:

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

Гарне рішення з кодексу. Я взяв на себе сміливість реалізувати його версію в 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]інструкцію


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

}

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

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)

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("------------------------------");
}

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

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

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

ця відповідь була б більш корисною, якщо ви опишете порядок зростання свого рішення
Томас,

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

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


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

O (N 2 )

також дає дві впорядковані пари- (a, b) і (b, a)


Ви можете згадати мову, чи є пари (a, b) і (b, a) унікальними, і на яке питання це відповідає (запитання не містить явного - I am not sure … Thanks for comments). Ви можете позначити колоту за складністю ближче до O (n²).
сіра борода

0

Я можу це зробити в O (n). Дайте мені знати, коли ви хочете відповіді. Зауважте, що це включає просто проходження масиву один раз без сортування тощо. Я також повинен зазначити, що він використовує комутативність додавання і не використовує хешів, а витрачає пам'ять.


використання системи; використовуючи 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();
        }
    }
}

В основному, щоб уникнути хешів, ми повинні створити таблицю, яка може приймати випадкові вставки за дещо довільними показниками. Тому я використовую M, щоб переконатися, що є достатньо елементів, і попередньо виділити суміжний набір, хоча більшість не буде використовуватися. Хеш-набір піклується про це безпосередньо.
AbstractDissonance

Отже, ви використовуєте хеш-набір із простою хеш-функцією та розміром, що перевищує максимальне значення вашої хеш-функції?
Кріс Хопман

Також ви можете також використовувати функцію ідентичності для вашої хеш-функції. Тобто, покладіть [k] на a [k] -th "bin".
Кріс Хопман

Оскільки [k] і X - a [k] використовуються індекси, а я використовую масив, це означає, що мінімальний індекс не може бути 0. Отже, я просто додаю дуже велике число, щоб перемістити їх вгору. Якщо можна було зробити хеш-функцію, яка працювала для довільних значень, тоді вони могли використовувати простий список, не виконуючи цього зсуву. Переміщення + попереднє розташування допомагає уникнути необхідності створювати хеш (або можна думати про дуже простий (і швидкий) хеш).
АнотаціяДісонанс

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

Дуже загадково .... ви використовуєте Stringify (O (n) час і простір) для кожної ітерації ..
Aviad


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.