这是interview question。有两个数组A1
和A2
。找出A2
中A1
中反向排序的数字对。A1 = [2 6 5 8 1 3]
。例如,A2 = [1 2 3 4 5 6]
,(1, 2), (1, 5), (1, 6), (5, 6), (3, 5), (3, 6)
。答案:{{1}}。
O(N ^ 2)算法是微不足道的。有没有更好的算法?你觉得怎么样?
答案 0 :(得分:4)
如果你有A1 = 1111122222
和A2 = 2222211111
这样的模式,那么你将输出(N / 2) 4 对。因此,在最坏的情况下,你不能比O(N 4 )做得更好。
下面是一个O(N 4 )解决方案,它处理重复项,一些数字只出现在两个列表中的一个中。请注意,虽然在最坏的情况下它是O(N 4 ),但它的平均情况O(N 2 )更有可能,类似于快速的复杂性-sort。
index = {} # dictionary of lists defaulting to []
for i in 0..len(A2):
index[A2[i]].append(i)
for i1 in 0..len(A1):
for j1 in i+1..len(A1):
for i2 in index[A1[i1]]:
for j2 in index[A1[j1]]:
if i2 != j2 and i1 < j1 != i2 < j2:
print A1[i1], A1[j1]
如果我们稍微放宽输出格式以允许输出(1, 2) * 7
以指示7次反转,那么我们可以做得更好。首先压缩列表,为示例提供[(2, 1), (6, 2), (5, 3), (8, 4), (1, 5), (3, 6)]
。使用稳定排序对数组进行排序:首先使用每个元组中的第一个项目,然后使用元组中的第二个项目对列表的另一个副本进行排序。然后使用像here那样的自适应合并排序,但不是计算我们生成的输出反转。这是一个O(NlogN)解决方案。
答案 1 :(得分:2)
如果两个数组都有相同的元素而A1是重排的A2(已排序),那么我们可以修改Merge Sort来计算A1中存在的反转数。
答案 2 :(得分:1)
我认为这个算法非常接近最好的算法。如果我们放弃构建trie(n ^ 2分配)的计算成本,我们将花费n(n-1)/ 2次操作。它以某种方式使用trie使对检查成本不变。如果需要,你可以以len(a)+ len(b)为代价扫描两个数组并推断出什么是MAX:
#include "stdio.h"
#include "stdlib.h"
#define MAX 9
#define AEL 6
#define BEL 6
int main(){
int b[BEL] = {2,6,5,8,1,3};
int a[AEL] = {1,2,3,4,5,6};
int **trie = calloc(MAX,sizeof(int*));
int i,j;
for(i = 0; i < MAX; i++){
trie[i] = calloc(MAX,sizeof(int));
}
for(i = 0; i < AEL; i++){
for(j = i+1; j < AEL; j++){
trie[a[i]][a[j]] = 1;
}
}
for(i = 0; i < BEL; i++ ){
for(j = i+1; j < BEL ; j++){
if(trie[b[j]][b[i]]){
printf("(%d %d) ",b[j],b[i]);
}
}
}
return 0;
}