C中具有相等总和的唯一对

时间:2019-03-20 10:56:24

标签: c algorithm time-complexity

眼前的问题是:

问题8。给定未排序的数组A []。任务是在未排序的数组中以相等的总和打印所有唯一对。考虑输入:A [] = {6,4,12,10,22,54,32,42,21,11}
说明解决上述问题的方法,并使用任何一种编程语言C / C ++ / Python / Java编写代码。以上问题的时间复杂度是多少?

这是我对上述问题的解决方案(在C中):

//get all courses and render index page
app.get("/courses", function(request, response) {
    CourseModel.find({}, {load: ["students"]}, function(error, result) {
        if(error) {
            return response.status(401).send({ "success": false, "message": error});
        }
        response.render("courses/index", {results: result});
    });
});

我的逻辑是一次取一个元素,并将其和其他元素相加,对于每次这样的迭代,将另外两个唯一的元素对的和相比较。 例如,当i = 0时,j = 3,则arr [i] + arr [j] = 16。当k = 1,l = 2时,arr [k] + arr [1] = 16。由于这些对是唯一的(6,10)和(4,12),并且它们的总和相等,因此我将它们打印出来。 请注意,这些对被假定为无序对,因此(a,b)与(b,a)相同,因此我们不必重复,因为它们必须是唯一的。

我的问题是:我知道我的代码几乎是O(n ^ 4)。如何进一步改善/优化它?

5 个答案:

答案 0 :(得分:1)

首先,您要预先计算每对的总和,并将结果保存在矩阵PAIRSUM中。

PAIRSUM(0, 0) = 12
PAIRSUM(0, 1) = 10 a s o

接下来,您遍历PAIRSUM并查看其中2个条目相似的地方。

因此,您将大问题简化为较小的问题,在该问题中,您检查了2个数字的相等性,而不是2个数字和的相等性。

为此,您保留一个向量PAIR,其中在索引X上的项保留在PAIRSUM中,总和为X

例如PAIR(10) = { {0, 1} }

您还可以在PAIRSUM中仅考虑对角线上方的矩阵,因此索引(i,j)具有i>j

答案 1 :(得分:1)

在C ++,Python或Java中,这会更容易,因为这些语言提供了高级容器。在Python中,您可以使用defaultdict(list),其中的键将是和,值是给出该和的对的列表。

然后,您只需要处理唯一对(N 2 / 2)

result = collections.defaultdict(list)
for i, a in enumerate(A):
    for b in A[i+1:]:
        result[a+b].append((a,b))

在C语言中,它会稍微复杂一些,因为您没有高级的直接访问指令。如果您会浪费一些内存,并且只有很少的数字(例如此处),则可以说最高的总和将小于输入数组中最大数字的两倍,然后直接分配该大小的数组。这样,您可以确保直接从总和中访问。从那里,您只需要使用成对的链表即可,仅此而已。作为奖励,您甚至可以获得汇总的排序列表。

我不能假设数量太少,您将必须建立一个直接访问容器。使用N * N / 2作为大小(N为A的长度)和sum%size作为哈希函数的哈希类型容器就足够了。

为完整起见,下面是一个可能的C代码,没有做小数假设(此代码不仅显示所有对,而且显示重复的对):

#include <stdio.h>
#include <stdlib.h>

// a node in a linked list of pairs
struct pair_node {
    int first;
    int second;
    struct pair_node *next;
};

// a slot for a hash type containers of pairs indexed by their sum
struct slot {
    int number;
    struct pair_node *nodes;
    struct slot *next;
};

// utility function to find (or create) a slot for a sum
struct slot* find_slot(struct slot **slots, int size, int sum) {
    struct slot *slt = slots[sum%size];
    while (slt != NULL) {
        if (slt->number == sum) {
            return slt;
        }
        slt = slt->next;
    }
    slt = malloc(sizeof(struct slot));
    slt->number = sum;
    slt->nodes = NULL;
    slt->next = slots[sum%size];
    slots[sum%size] = slt;
    return slt;
}

int main() {
    int A[] = {6,4,12,10,22,54,32,42,21,11};  // the array of numbers
    int N = sizeof(A) / sizeof(A[0]);

    int arr_size = N * N / 2;   // size of the hash table of pairs
    struct slot** result = malloc(arr_size * sizeof(struct slot *));
    for (int i=0; i<arr_size; i++) {
        result[i] = NULL;
    }

    // process unique pairs
    for (int i=0; i<N-1; i++) {
        for (int j=i+1; j<N; j++) {
            int sum = A[i] + A[j];
            // allocate and initialize a node
            struct pair_node *node = malloc(sizeof(*node));
            node->first = A[i];
            node->second = A[j];

            // store the node in the hash container
            struct slot *slt = find_slot(result, arr_size, sum);
            node->next = slt->nodes;
            slt->nodes = node;
        }
    }

    // display the result
    for (int i=0; i<arr_size; i++) {
        for (struct slot* slt=result[i]; slt != NULL;) {
            printf("%d :", slt->number);
            struct pair_node *node = slt->nodes;
            while(node != NULL) {
                printf(" (%d,%d)", node->first, node->second);
                node = node->next;
                free(node);                // free what has been allocated
            }
            printf("\n");
            struct slot *old = slt;
            slt = slt->next;
            free(old);
        }
    }
    free(result);
    return EXIT_SUCCESS;
}

答案 2 :(得分:0)

C代码,用于计算所有总和并将总和与索引一起存储在结构数组中。然后,我们对结构进行排序并以相同的总和打印相邻的结构元素。

#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>

// for debugging
#define debug(...)  ((void)0) // printf(__VA_ARGS__)

// two indexes and a sum
struct is_s {
    // one index inside the array
    size_t i;
    // the other index also inside the array
    size_t j;
    // no idea, must be random
    int sum;
};

// used for qsoring the struct is_s
static int is_qsort_compare_sum(const void *a0, const void *b0) {
    const struct is_s * const a = a0;
    const struct is_s * const b = b0;
    return a->sum - b->sum;
}

int unique_pairs(const size_t len, const int arr[len]) {
    if (len <= 1) return 0;
    // The number of unsorted combinations must be n!/(2!*(n-2)!)
    const size_t islen = len * (len - 1) / 2; // @MOehm
    debug("%zu\n", islen);

    struct is_s * const is = malloc(islen * sizeof(*is));
    if (is == NULL) {
        return -ENOMEM;
    }

    size_t isidx = 0;
    for (size_t i = 0; i < len; ++i) {
        for (size_t j = i + 1; j < len; ++j) {
            assert(isidx < islen); // just for safety
            struct is_s * const p = &is[isidx++];
            p->i = i;
            p->j = j;
            p->sum = arr[i] + arr[j];
            debug("[%zu]=[%zu]=%d [%zu]=%d %d\n", isidx, p->i, arr[p->i], p->j, arr[p->j], p->sum);
        }
    }

    qsort(is, islen, sizeof(*is), is_qsort_compare_sum);

    for (size_t i = 0; i < islen - 1; ++i) {
        debug("([%zu]=%d,[%zu]=%d)%d = ([%zu]=%d,[%zu]=%d)%d\n", 
            is[i].i, arr[is[i].i], is[i].j, arr[is[i].j], is[i].sum,
            is[i+1].i, arr[is[i+1].i], is[i+1].j, arr[is[i+1].j], is[i+1].sum
        );
        if (is[i].sum == is[i + 1].sum) {
            printf("(%d,%d),(%d,%d) = %d\n",
                arr[is[i].i], arr[is[i].j],
                arr[is[i+1].i], arr[is[i+1].j], is[i].sum);
        }
    }

    free(is);

    return 0;
}

int main(void) {
    const int arr[] = {6,4,12,10,22,54,32,42,21,11};
    return unique_pairs(sizeof(arr)/sizeof(*arr), arr);
}

我得到的结果是:

(6,10),(4,12) = 16
(10,22),(21,11) = 32
(12,21),(22,11) = 33
(22,21),(32,11) = 43
(32,21),(42,11) = 53
(12,42),(22,32) = 54
(10,54),(22,42) = 64

正如@Bathsheba指出的那样,我想知道这是否正确,我认为最坏的情况是O(n * n)。

答案 3 :(得分:0)

可以在O(N ^ 2 * log(N ^ 2)* M)中完成,其中M是具有相同总和的最大对(i,j),因此在最坏的情况下是O(N ^ 3 * log(N))。

让每对配对0 <= i,j

您不必担心(i,j)的以下对具有和,因为在处理以下对时,它们将计算在内。

答案 4 :(得分:0)

这是一个 Java 解决方案:

import java.util.*;

class Duplicate {
  public static void main(String[] args) {
    
    int [] a = {5,3,1,4,5,6,3,7,0,10,6,4,9,1};
    
    List<Integer> li = new ArrayList<Integer>();
    
    int p1=0, p2=0;
    
    for(int i=0; i<a.length;i++) {
      for(int j=i+1; j<a.length;j++){
        
        if(a[i]+a[j] == 10) {
          
          p1 = a[i];
          p2 = a[j];
          
          if(!li.contains(Math.abs(p2-p1))) {
              
            li.add(Math.abs(p2-p1));
            
            System.out.println("Pairs" + ":" + p1 + "," + p2);
          }
        }
        p1=0;
        p2=0;
      }
    }
    
  }
}