算法与数据结构(8)——逆序对(归并排序)

逆序对

关于归并排序和快速排序的第一个衍生问题就是逆序对,例如下图中的数组{8,6,2,3,1,5,7,4},其中{2,3}就是一个顺序对,而{2,1}就是一个逆序对。

归并排序

要解决此问题此时可以依赖于归并过程,例如以下动画,两个分别排好序的子数组{2,3,6,8,}和{1,4,5,7,}:

  • 首先1比2小,意味1比2后面的所有元素都小,计数器可直接加4,指向1的下标后移。
  • 4大于2,不考虑,指向2的下标后移。
  • 4大于3,不考虑,指向3的下标后移。
  • 4小于6,意味4比6后面的所有元素都小,计数器可直接加2,指向4的下标后移。
  • 依次类推
public class InversionCount {
    private InversionCount() {
    }

    private static long merge(Comparable[] arr, int l, int mid, int r){

        Comparable[] aux = Arrays.copyOfRange(arr, l, r+1);

        long res = 0L;

        int i = l, j = mid+1;
        for(int k = l; k <= r; k ++){

            if(i > mid){
                arr[k] = aux[j-l];
                j++;
            }else if(j > r){
                arr[k] = aux[i-l];
                i ++;
            }else if(aux[i-l].compareTo(aux[j-l]) <= 0){
                arr[k] = aux[i-l];
                i ++;
            }else {  //右边小于左边
                arr[k] = aux[j-l];
                j ++;

                // 重点的部分啦
                res += (long)(mid - i + 1);
            }
        }
        return res;
    }

    private static long solve(Comparable[] arr, int l, int r){

        if(l >= r) return 0L;

        int mid = (r-l)/2 + l;
        long res1 = solve(arr, l, mid);
        long res2 = solve(arr, mid+1, r);

        return res1 + res2 + merge(arr, l, mid, r);
    }

    public static long solve(Comparable[] arr){
        int n = arr.length;
        return solve(arr, 0, n-1);
    }

    public static void main(String[] args) {
        Integer[] arr = {1,2,3,4,5,6,7,0};
        System.out.println(solve(arr));
    }
}

你可能感兴趣的:(算法与数据结构)