数组中逆序对的个数

import com.google.common.base.Preconditions;

/**
 * 数组中的逆序对:数组中任意的两个数字,如果前一个数字大于后一个数字,则这两个数字就构成了一个逆序对。
 */
public class InverseParisInArray {

    /**
     * 求指定数组中,逆序对的个数。
     */
    public static int getInverseParisCountByMergeSort(int[] array) {

        Preconditions.checkArgument(null != array && array.length > 0);

        // 存储逆序对个数的容器
        int[] countContainer = new int[1];

        mergeSort(array, 0, array.length - 1, countContainer);
        return countContainer[0];
    }


    /**
     * 求指定数组中,逆序对的个数。
     *
     * 思路:
     *  1)把数组分隔成两个子数组A和B,先统计出子数组中逆序对的个数 并且 将子数组进行排序,然后再统计出这两个子数组之间的逆序对的个数。
     *  2)排序的目的是为了避免在之后的统计中出现重复统计。
     *  3)在对子数组进行统计时,仍然将数组分为两个子数组,故这里使用递归来实现该功能。
     *
     * 时间复杂度:O(nlogn)
     *
     * @param array
     * @param low
     * @param high
     * @param countContainer
     * @return
     */
    public static int[] mergeSort(int[] array, int low, int high, int[] countContainer) {

        if (low < high) {                       // 当low=high时,说明已经分解到单个元素了
            int mid = (low + high) >> 1;
            mergeSort(array, low, mid, countContainer);          // 递归地对左半部分进行分解
            mergeSort(array, mid + 1, high, countContainer);     // 递归地对右半部分进行分解

            merge(array, low, mid, high, countContainer);        // 分解已完成,将左子序列和右子序列进行合并
        }
        return array;
    }


    public static void merge(int[] array, int low, int mid, int high, int[] countContainer) {

        int[] temp = new int[high - low + 1];   // 临时数组,长度与原数组长度一致

        int i = mid;            // 左边序列的最后一个元素的下标
        int j = high;           // 右边序列的最后一个元素的下标
        int k = temp.length - 1;              // 临时数组temp的下标

        /**
         * 把较大的数先copy到临时数组temp中:
         */
        while (i >= low && j > mid) {
            if (array[i] > array[j]) {
                temp[k--] = array[i--];
                countContainer[0] += j - mid;
            } else {
                temp[k--] = array[j--];
            }
        }

        // 如果左边的序列中还有未copy过的元素,则把左边剩余的元素copy临时数组temp中。
        while (i >= low) {
            temp[k--] = array[i--];
        }

        // 如果右边的序列中还有未copy过的元素,则把右边剩余的元素copy临时数组temp中。
        while (j > mid) {
            temp[k--] = array[j--];
        }

        // 用排好序的临时数组temp覆盖原数组
        for (int t = 0; t < temp.length; t++) {
            array[t + low] = temp[t];
        }
    }
    

    public static void main(String[] args) {

//        int[] array = {7, 6, 5, 4};
        int[] array = {7, 5, 6, 4};
//        int[] array = {4, 5, 6, 7};
        int count = getInverseParisCountByMergeSort(array);
        System.out.println(count);

    }

}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值