如何查找数组中的反转次数?

时间:2015-10-14 04:27:15

标签: java arrays sorting compare inversion

基本上我正在尝试用Java编写一个算法来确定数组中乱序的对数。因此,如果我们取i和j并且j在阵列中的位置比i高,但是A [i]> A [j]然后它将这两个数字计为反转。目前这就是我所拥有的:

for(int i = 0; i<n-1; i++){
    if (A[i] > A[i+1]){
        k++;

这样做只是比较了彼此旁边的对,所以现在我试图修改它以找到数组中的任何两个数字,其中较低位置的值高于较高位置的数字。我知道如何做这样的事情,但我希望运行时间为(n + k),其中n是数组的长度,k是数组中的反转次数。

编辑:这是我尝试实现插入排序:

int k = 0;
int [] A = {5, 4, 3, 2, 1};
int n = A.length;
for(int i = 1; i < n; i++){
    int temp = A[i];
    int j;
    for (j = i - 1; j >=0 && temp < A[j]; j--){
        A[j + 1] = A[j];
    A[j + 1] = A[j];
        k++;

k应该跟踪多少次反转。对于数组5,4,3,2,1,我返回的数字是6.是吗?

2 个答案:

答案 0 :(得分:2)

解决方案是实现插入排序,并计算交换一对相邻元素的次数。这是有效的,因为插入排序只为每次反转执行交换。事实上,它的运行时间是 O n + k ),正如您所要求的那样。

至于问题第二部分 - 这是更正后的插入排序算法:

for (int i = 1; i < n; i++) {
    int temp = A[i];
    int j;
    for (j = i - 1; j >= 0 && temp < A[j]; j--) {
        A[j + 1] = A[j];
        k++;  // Number of inversions
    }
    A[j + 1] = temp;
}

额外注意:计算数组反转的有效方法是修改合并排序算法,该算法在 O n log n >中运行) 时间。但是,当 k 很小时, O n + k )大约 O n ),小于 O n log n )。实际上,合并排序的最佳时间仍然是 O n log n ),而插入排序最好case是 O n )。因此,合并排序不会回答O​​P对 O n + k )的问题算法

答案 1 :(得分:0)

数组的反转计数表示 - 数组的排序距离(或接近)。如果数组已经排序,则反转计数为0.如果数组按相反顺序排序,则反转计数最大。 从形式上讲,如果a [i]> 1,则[i]和[j]两个元素形成反转。 a [j]和i&lt; j示例: 序列2,4,1,3,5有三个反转(2,1),(4,1),(4,3)。

对于每个元素,计算在其右侧并且小于它的元素数量。

int getInvCount(int arr[], int n)
{
  int inv_count = 0;
  int i, j;

  for(i = 0; i < n - 1; i++)
    for(j = i+1; j < n; j++)
      if(arr[i] > arr[j])
        inv_count++;

  return inv_count;
}

/* Driver progra to test above functions */
int main(int argv, char** args)
{
  int arr[] = {1, 20, 6, 4, 5};
  printf(" Number of inversions are %d \n", getInvCount(arr, 5));
  getchar();
  return 0;
}