【问题标题】:Need help count inversions with merge sort需要帮助使用归并排序计算反转
【发布时间】:2014-10-31 09:24:29
【问题描述】:

以下代码通过归并排序计算数组 numsi,j 对,使得 j>i && nums[i] > nums[j])中的反转。

是否可以使用相同的方法来计算像j>i && nums[i] > 2*nums[j] 这样的特殊反转的数量?

我应该如何修改这段代码?

public static void main (String args[])
{
    int[] nums = {9, 16, 1, 2, 3, 4, 5, 6};
    System.out.println("Strong Inversions: " + countInv(nums));         
}

public static int countInv(int nums[])
{  
    int mid = nums.length/2;
    int countL, countR, countMerge;

    if(nums.length <= 1)
    {
        return 0;
    }

    int left[] = new int[mid];
    int right[] = new int[nums.length - mid];

    for(int i = 0; i < mid; i++)
    {
        left[i] = nums[i];
    }

    for(int i = 0; i < nums.length - mid; i++)
    {
        right[i] = nums[mid+i];
    }

    countL = countInv (left);
    countR = countInv (right);

    int mergedResult[] = new int[nums.length];
    countMerge = mergeCount (left, right, mergedResult);

    for(int i = 0; i < nums.length; i++)
    {
        nums[i] = mergedResult[i];
    }

    return (countL + countR + countMerge);
}


public static int mergeCount (int left[], int right[], int merged[])
{
    int a = 0, b = 0, counter = 0, index=0;

    while ( ( a < left.length) && (b < right.length) )
    {
        if(left[a] <= right[b])
        {
            merged [index] = left[a++];
        }
        else 
        {   
            merged [index] = right[b++];
            counter += left.length - a;
        }
        index++;
    }

    if(a == left.length)
    {
        for (int i = b; i < right.length; i++)
        {
            merged [index++] = right[i];
        }
    }
    else
    {
        for (int i = a; i < left.length; i++)
        {
            merged [index++] = left[i];
        }
    }
    return counter;
} 

我试过了

while ((a < left.length) && (b < right.length)) {
    if (left[a] <= right[b]) {
        merged[index] = left[a++];
    } else {
        if (left[a] > 2 * right[b]) {
            counter += left.length - a;
        }
        merged[index] = right[b++];
    }
    index++;
}

但是while循环中有一个错误,当left[a]&lt;2*right[b]left[a+n] maybe&gt;2*right[b]时,例如左数组是{9,16}而右数组是{5,6}9但是16>2*5。我的代码只是跳过这样的情况,结果数小于应有的值

【问题讨论】:

  • 顺便说一句,不要复制数组。您的所有工作都可以在nums 中完成。我敢打赌,如果您避免在每次递归调用时创建和处理数组,您将获得大量时间。实际上,在进行递归调用之前进行合并或多或少等效(此外,您的函数将是尾递归的)。
  • 哦,如果你还想继续复制数组,你可以使用System.arraycopy(见documentation)。例如,左初始化:System.arraycopy(nums, 0, left, 0, mid)

标签: java algorithm sorting mergesort


【解决方案1】:

mergeCount 中的while 循环有两个功能:将leftright 合并到merged 中,并计算leftright 倒置的数量。对于特殊的反转,最简单的方法是将循环分成两部分,先计算反转然后合并。计数反转的新触发器是left[a] &gt; 2*right[b]

之所以有两个循环,是因为计算特殊反转需要合并left2*right,排序需要合并leftright。或许可以在一个循环中使用三个不同的索引,但逻辑会更复杂。

【讨论】:

  • 是的,我确实尝试将该触发器放在 while 循环中,
  • @Ryan 您是否拆分了循环并单独保留合并条件?否则将无法正常工作。
  • 我已经编辑了我的问题,我不知道这是否是你想说的。我是新手,请帮忙。
【解决方案2】:
    while ( ( a < left.length) && (b < right.length) ) {
        if(left[a] <= right[b]) {
            merged [index] = left[a++];
        } else {
            counter += updateCounter(right[b],a,left);
            merged [index] = right[b++];
        }
        index++;
        //Rest of the while loop
    }
    //Rest of the mergeCount function
}

public static int updateCounter(int toSwitch, int index, int[] array) {
    while(index < array.length) {
        if(array[index] >= 2*toSwitch)
            break;
        index++;
    }
    return array.length-index;
}

效率不是很高,但它应该可以完成工作。你用a初始化index,因为低于a的元素永远不会满足条件。

【讨论】:

  • 合并和计算“反转”将不再在单个循环中工作。
  • 确实如此。对不起。我将尽快使用可行的解决方案编辑我的帖子。
猜你喜欢
  • 2016-07-22
  • 1970-01-01
  • 2018-11-20
  • 2014-08-04
  • 1970-01-01
  • 2011-08-11
  • 2021-03-22
  • 1970-01-01
  • 2019-02-12
相关资源
最近更新 更多