眼前的问题是:
问题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)。如何进一步改善/优化它?
答案 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;
}
}
}
}