我得到两个长度相等的整数序列,例如
3 1 2 5 4
5 3 2 1 4
我想找到两者之间的Kendall Tau距离,即序列之间的反转对数。例如,我们在第一个序列中有(3,5)(3在5之前),在第二个序列中有(5,3)。我做了一个快速的O(n ^ 2)算法来检查数字,但对于长度为40,000及以上的大型序列,它的计算能力太强。我已经读过,我可以计算进行冒泡排序的倒数,将第一个序列转换为第二个序列,但那又是O(n ^ 2)。
unsigned short n, first[50001], second[50001], s;
int sum = 0;
cin >> n;
for(int i=1; i<n+1; i++){
cin >> first[i];
}
// in the second array exchange the actual entries in the sequence with their indices
// that way we can quickly check if a pair is inverted
for(int i=1; i<n+1; i++){
cin >> s
second[s]=i;
}
for(int i=1; i<n+1; i++){
for (int j = i+1; j < n+1; j++)
// i < j always
// when we check the indices of the respective entries in the second array
// the relationship should stay otherwise we have an inversion
if(second[first[i]]>=second[first[j]])sum++;
}
答案 0 :(得分:1)
这个问题似乎与数组中的反转计数问题密切相关,不同之处在于,在这种情况下,反转意味着“元素相对于另一个序列交换”而不是“元素乱序。 “由于有一个很好的O(n log n)时间算法来计算反演,似乎试图找到一种方法来调整该算法来解决这个特定问题似乎是合理的。
用于计数反转的分而治之算法基于mergesort并假设给定序列中的任何两个元素有一种快速(O(1) - 时间)方式来比较它们以查看它们是否在适当的顺序。如果我们能找到一种方法以某种方式注释第二个序列的元素,以便在时间O(1)中我们可以确定该序列中的任何元素对是按顺序还是乱序,那么我们就可以运行快速计数反演算法,以获得您正在寻找的答案。
这是一种方法。创建一些辅助数据结构(比如,平衡的BST),它将第一个数组的元素与第一个数组中的索引相关联。然后,复制第二个数组,用第一个数组中相应的位置注释每个元素。这总共花费时间O(n log n)。然后,运行标准O(n log n)-time算法来计算第二个数组中的反转,除非在比较元素时,通过它们的相关索引而不是它们的值进行比较。这总共花费时间O(n log n)来完成。