Tìm một cặp phần tử từ một mảng có tổng bằng một số nhất định


122

Cho dãy n số nguyên và cho trước một số X, hãy tìm tất cả các cặp phần tử duy nhất (a, b) có tổng của chúng bằng X.

Sau đây là giải pháp của tôi, nó là O (nLog (n) + n), nhưng tôi không chắc liệu nó có tối ưu hay không.

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
Giải pháp O (n) có thể thực hiện được nếu bạn gộp mọi thứ vào một tập hợp O (1) nào đó thay vì sắp xếp mảng.
Anon.

1
@Anon Bạn có thể cho biết thêm chi tiết, làm thế nào để xây dựng một bộ như vậy?
Gin

3
Sử dụng hàm băm. Hầu hết các ngôn ngữ sẽ có một O (1) HashSet được khấu hao ở đâu đó trong thư viện tiêu chuẩn của chúng.
Anon.

15
Một nit nhỏ - O (nLog (n) + n) là O (nLog (n)). Ký hiệu Big O chỉ giữ lại thuật ngữ chi phối và loại bỏ tất cả các thuật ngữ bậc thấp hơn.
pjs

2
Lưu ý đánh giá ngắn mạch và giải quyết từng việc: while((arr[i] + arr[j]) <= sum && i < j)nên có while( i < J && arr[i] + arr[j] <= sum ). (tương tự cho các subloop giây)
wildplasser

Câu trả lời:


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
Bạn thậm chí có thể làm điều đó trong một lần lặp qua mảng, bằng cách đặt câu lệnh if của bạn từ vòng lặp thứ hai, ngay sau phép gán băm trong vòng lặp đầu tiên.
Alexander Kondratskiy

4
Lưu ý nhỏ: Điều này (cũng như gợi ý của Alexander) sẽ in kép một số cặp, cho dù tính duy nhất của một cặp được xác định bởi chỉ số (như có thể được ngụ ý từ câu trả lời này) hoặc theo giá trị (như có vẻ như trong OP). Có thể có khá nhiều (O (n ^ 2)) cặp duy nhất theo chỉ mục, ví dụ arr=[1,2,1,2,1,2,1,...]. Đối với tính duy nhất theo giá trị, có vẻ như một bảng băm khác được khóa bởi một cặp giá trị sẽ thực hiện thủ thuật. Vẫn là một câu trả lời hay, nhỏ gọn, thanh lịch. +1
William

2
@codaddict Nhưng nếu mảng rất lớn thì sao? Ý tôi là phạm vi giá trị trong nó rất lớn? Vì vậy, giải pháp băm khi đó sẽ ít thực tế hơn. Bất kỳ phương pháp thay thế và tối ưu nào cho giống nhau?
Prashant Singh

15
Nếu có trùng lặp thì sao?
zad

2
Liệu hash(K - arr[i]) != ibằng cách nào đó kiểm tra cả sự hiện diện và việc thiếu một trận đấu? Tôi mong đợi có một cuộc kiểm tra riêng cho sự hiện diện.
Joseph Garvin

185

Có 3 cách tiếp cận cho giải pháp này:

Gọi tổng là T và n là kích thước của mảng

Phương pháp 1:
Cách đơn giản để làm điều này là kiểm tra tất cả các kết hợp (n chọn 2). Tìm kiếm đầy đủ này là O (n 2 ).

Phương pháp 2: 
 Một cách tốt hơn sẽ là sắp xếp mảng. Điều này nhận O (n log n)
Sau đó, với mỗi x trong mảng A, sử dụng tìm kiếm nhị phân để tìm Tx. Điều này sẽ lấy O (nlogn).
Vì vậy, tìm kiếm tổng thể là O (n log n)

Cách tiếp cận 3:
Cách tốt nhất là chèn mọi phần tử vào bảng băm (không cần sắp xếp). Điều này nhận O (n) là chèn thời gian không đổi.
Khi đó với mọi x, chúng ta chỉ có thể tìm phần bù của nó, Tx, là O (1).
Nhìn chung thời gian chạy của phương pháp này là O (n).


Bạn có thể tham khảo thêm tại đây . Xin cảm ơn.



Bạn sẽ tạo bảng băm cho các phần tử của mảng như thế nào?
Satish Patel

Tham khảo liên kết tôi đã chia sẻ. Chúng ta có thể có một mảng song song để lưu trữ phần tử dưới dạng chỉ mục hoặc bạn có thể thêm các phần tử vào bảng băm và sử dụng hàm chứa trên chúng. Xin lỗi vì trả lời muộn như vậy.
kinshuk

11
Bạn có thể nhận được một số dương sai nếu có một phần tử bằng chính xác một nửa tổng mục tiêu.
Florian F

2
@Florian_F Bạn không thể chỉ trường hợp đặc biệt khi bạn có một phần tử chính xác là một nửa?
Joseph Garvin

1
@jazzz Ý tôi là HashMap ở đây, mặc dù HashSet cũng sẽ làm được. Đây là cách triển khai - github.com/kinshuk4/AlgorithmUtil/blob/master/src/com/vaani/… . Hy vọng nó giúp.
kinshuk 4

64

Triển khai trong Java: Sử dụng thuật toán codaddict (Có thể hơi khác một chút)

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

}
}

Đối với đầu vào = {2,45,7,3,5,1,8,9}và nếu Tổng là10

Các cặp đầu ra:

3,7 
8,2
9,1

Một số lưu ý về giải pháp:

  • Chúng tôi lặp lại một lần duy nhất qua mảng -> O (n) thời gian
  • Thời gian chèn và tra cứu trong Hash là O (1).
  • Thời gian tổng thể là O (n), mặc dù nó sử dụng thêm không gian về mặt băm.

1
Điều này CHỈ tốt nếu mảng đầu vào không có bản sao.
Naren

2
@Naren: Không có gì khác biệt ngay cả khi có các bản sao trong mảng đã cho
abhishek08aug

1
nó không thực hiện những gì các codaddicts đã viết, và những gì bạn đã làm, mặc dù nó hoạt động, là phức tạp không cần thiết. Nó là vô nghĩa để put(k-input[i], input[i])(codaddicts puts chỉ số như giá trị đó là hữu ích.) Những gì bạn viết có thể được đơn giản hóa đểfor (i:input){ if (intSet.contains(sum-i) { print(i + "," + (sum-i) ); } else {intSet.add(i)}
Adrian Shum

1
Được rồi, cảm ơn. Với mục đích tham khảo cho người khác, tôi chỉ tạo một chủ đề khác để những ai đang gặp khó khăn trong việc phân tích cách giải pháp này hoạt động có thể hiểu đúng. Đây là liên kết: stackoverflow.com/questions/33274952/…
John

2
@ abhishek08aug điều này sẽ không hoạt động trong {1, 1, 1}
jbakirov

8

Giải pháp trong java. Bạn có thể thêm tất cả các phần tử Chuỗi vào một Danh sách chuỗi chuỗi và trả về danh sách. Ở đây tôi chỉ đang in nó ra.

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

Triển khai 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])

Đầu ra:

1 + 4
2 + 3

2
nhìn vào ... sẽ overhead cho các phần tử tìm kiếm
Nikhil Rupanawar

4

C ++ 11, độ phức tạp thời gian chạy 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

Đây là một giải pháp phù thủy tính đến các mục trùng lặp. Nó được viết bằng javascript và giả sử mảng được sắp xếp. Giải pháp chạy trong thời gian O (n) và không sử dụng thêm bất kỳ bộ nhớ nào ngoài biế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;
}

Tôi đã giải quyết điều này trong một cuộc phỏng vấn cho một tập đoàn lớn. Họ đã lấy nó nhưng không phải tôi. Vì vậy, ở đây nó là dành cho tất cả mọi người.

Bắt đầu ở cả hai bên của mảng và từ từ làm việc theo cách của bạn vào trong để đảm bảo đếm các bản sao nếu chúng tồn tại.

Nó chỉ đếm các cặp nhưng có thể được làm lại thành

  • tìm nửa kia
  • tìm cặp <x
  • tìm cặp> x

Thưởng thức!


Có gì những dòng này làm ?: if(distI > distK) while(_arr[++i]==curI); else while(_arr[--k]==curK);
Yuriy Chernyshov

Những dòng skip qua giá trị nhân bản từ cả hai phía và đếm chúng như cặp nếu họ là một phần của một tổng cặp = N
Drone Brain

3

Trê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)

Phương pháp luận: a + b = c, vì vậy thay vì tìm (a, b) chúng ta tìm a = c - b


Không chảo nếu bạn có bản sao trong đầu vào, như thế này: [3, 4, 3, 2, 5] và sum = 6
Anton Danilchenko

Đã sửa tất cả các trường hợp cạnh, bây giờ hãy thử
garg10may

2

Triển khai trong Java: Sử dụng thuật toán 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]);
        }
    }      

}

}

Đầu ra:

81, 79
79, 81

Nếu bạn cũng muốn các cặp trùng lặp (ví dụ: 80,80) thì chỉ cần loại bỏ && (Integer) mapping.get (ka [i])! = I khỏi điều kiện if và bạn đã sẵn sàng.


đối với C # điều này có thể hoạt động - 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]) { tính ++; }}} Console.WriteLine (count);
MukulSharma

2

Tôi vừa tham dự câu hỏi này trên HackerRank và đây là Giải pháp 'Mục tiêu C' của tôi :

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

Hy vọng nó sẽ giúp một ai đó.


cú pháp mã khó hiểu hơn chính thuật toán! :)
Rajendra Uppal

1

đây là việc triển khai O (n * lg n) bằng cách sử dụng thực hiện tìm kiếm nhị phân bên trong một vòng lặp.

#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

Trong trăn

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

Giải pháp tốt đẹp từ Codeaddict. Tôi đã tự do triển khai một phiên bản của nó trong 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

Để cho phép các cặp trùng lặp (1,5), (5,1), chúng ta chỉ cần loại bỏ && !result[sum-l]lệnh


1

Đây là mã Java cho ba cách tiếp cận:
1. Sử dụng Map O (n), HashSet cũng có thể được sử dụng ở đây.
2. Sắp xếp mảng và sau đó sử dụng BinarySearch để tìm phần bù O (nLog (n))
3. BruteForce truyền thống hai vòng 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

Một chương trình đơn giản trong java cho các mảng có các phần tử duy nhất:

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

Một đoạn mã Java đơn giản để in các cặp bên dưới:

    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

Một giải pháp khác trong Swift: ý tưởng là tạo một băm lưu trữ các giá trị của (sum - currentValue) và so sánh giá trị này với giá trị hiện tại của vòng lặp. Độ phức tạp là 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

Giải pháp của tôi - Java - Không có bản sao

    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

Điều này sẽ in các cặp và tránh các bản sao bằng thao tác bitwise.

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

Tôi đã bỏ qua cách viết mã bit và chỉ so sánh các giá trị chỉ mục. Giá trị này nhỏ hơn giá trị lặp của vòng lặp (i trong trường hợp này). Điều này sẽ không in các cặp trùng lặp và các phần tử mảng cũng trùng lặp.

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

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

câu trả lời này sẽ hữu ích hơn nếu bạn mô tả thứ tự phát triển của giải pháp của bạn
Thomas

0

Một Giải pháp có thể là điều này, nhưng không phải là tối ưu (Độ phức tạp của mã này là 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

Một phiên bản python đơn giản của mã tìm một cặp tổng bằng 0 và có thể được sửa đổi để tìm 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

Độ phức tạp thời gian chạy của hàm là O (n) và 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

nhỏ hơn o (n) nghiệm sẽ là =>

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

Sẽ thất bại đối với một số đầu vào nhất định. Thêm vào đó, bạn được yêu cầu trả lại một số tiền không phải paris
Aviad

0

Giải pháp trong Python sử dụng khả năng hiểu danh sách

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

O (N 2 )

cũng đưa ra hai cặp có thứ tự- (a, b) và (b, a)


Bạn có thể đề cập đến một ngôn ngữ, liệu các cặp (a, b) và (b, a) có phải là duy nhất hay không và câu hỏi này trả lời cho câu hỏi nào (câu hỏi không chứa câu rõ ràng - I am not sure … Thanks for comments). Bạn có thể biểu thị mức độ phức tạp gần với O (n²) hơn.
greybeard,

0

Tôi có thể làm điều đó trong O (n). Hãy cho tôi biết khi bạn muốn câu trả lời. Lưu ý rằng nó chỉ liên quan đến việc duyệt qua mảng một lần mà không cần sắp xếp, v.v. Tôi cũng nên đề cập rằng nó khai thác tính giao hoán của phép cộng và không sử dụng hàm băm nhưng lãng phí bộ nhớ.


sử dụng Hệ thống; sử dụng System.Collections.Generic;

/ * Có một cách tiếp cận O (n) bằng cách sử dụng một bảng tra cứu. Cách tiếp cận là lưu trữ giá trị trong một "thùng" có thể dễ dàng tra cứu (ví dụ: O (1)) nếu nó là ứng cử viên cho một tổng thích hợp.

ví dụ,

đối với mỗi a [k] trong mảng, chúng ta chỉ cần đặt nó vào một mảng khác tại vị trí x - a [k].

Giả sử chúng ta có [0, 1, 5, 3, 6, 9, 8, 7] và x = 9

Chúng tôi tạo một mảng mới,

giá trị chỉ mục

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

THÌ các giá trị duy nhất quan trọng là những giá trị có chỉ mục trong bảng mới.

Vì vậy, giả sử khi chúng ta đạt đến 9 hoặc bằng, chúng ta sẽ xem liệu mảng mới của chúng ta có chỉ số 9 - 9 = 0. Vì nó biết rằng tất cả các giá trị mà nó chứa sẽ thêm vào 9 (lưu ý trong lý do này rõ ràng là chỉ có 1 có thể có nhưng nó có thể có nhiều giá trị chỉ mục mà chúng ta cần lưu trữ).

Vì vậy, hiệu quả những gì chúng tôi làm cuối cùng là chỉ phải di chuyển qua mảng một lần. Bởi vì phép cộng có tính chất giao hoán, chúng tôi sẽ kết thúc với tất cả các kết quả có thể.

Ví dụ, khi chúng ta đến 6, chúng ta nhận được chỉ mục vào bảng mới của chúng ta là 9 - 6 = 3. Vì bảng chứa giá trị chỉ số đó nên chúng ta biết các giá trị.

Đây thực chất là đánh đổi tốc độ cho bộ nhớ. * /

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

Về cơ bản để tránh hàm băm, chúng ta phải tạo một bảng có thể chấp nhận việc chèn ngẫu nhiên tại các chỉ số hơi tùy ý. Do đó tôi sử dụng M để đảm bảo rằng có đủ phần tử và phân bổ trước một tập liền kề mặc dù hầu hết sẽ không được sử dụng. Một bộ băm sẽ trực tiếp giải quyết vấn đề này.
AbstractDissonance

Vì vậy, bạn đang sử dụng một bộ băm có hàm băm đơn giản và kích thước lớn hơn giá trị tối đa của hàm băm của bạn?
Chris Hopman,

Cũng có thể sử dụng hàm nhận dạng cho hàm băm của bạn tại thời điểm này. Tức là, đặt [k] tại "thùng" a [k] -th.
Chris Hopman,

Bởi vì a [k] và X - a [k] được sử dụng một chỉ số và tôi đang sử dụng một mảng, điều đó có nghĩa là chỉ số tối thiểu không thể bằng 0. Do đó, tôi chỉ cần thêm một số rất lớn để chuyển chúng lên. Nếu một người có thể tạo một hàm băm hoạt động cho các giá trị tùy ý thì họ có thể sử dụng một danh sách đơn giản mà không cần phải thực hiện chuyển đổi này. Việc dịch chuyển + định vị trước giúp tránh phải tạo một hàm băm (hoặc có thể nghĩ là một hàm băm rất đơn giản (và nhanh)).
AbstractDissonance

-1

Giải pháp 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);
}

Rất hiệu quả .... bạn đang sử dụng Stringify (O (n) thời gian và không gian) mỗi lần lặp ..
Aviad


-4

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

var z = (from a in arr from b in arr where 10 - a == b select new {a, b}). toList;

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.