【知识积累】在一个数组中,一个数比右边的数大,则这两个数称为逆序对,返回数组逆序对的个数

package com.example.demo.algorithm.D003;

/**
 * @Description :
 * 逆序对问题:理解归并排序的精髓
 *
 * 在一个数组中,一个数比右边的数大,则这两个数称为逆序对,返回数组逆序对的个数
 * 例子:[3,1,7,0,2]
 * 3的逆序对:3:1 3:0 3:2
 * 1的逆序对:1:0
 * 7的逆序对:7:0 7:2
 * 0的逆序对:没有
 * 2的逆序对:没有
 * 逆序对的个数为:3 + 1 + 2 = 6
 *
 * 流程:
 * 左组的数比右组的数大,产生逆序对 -> 右组的数比左组的数小,产生逆序对 -> 左组有多少个数比右组大,那么就产生多少对逆序对
 * 1、左组去marge,返回逆序对的个数
 * 2、右组去marge,返回逆序对的个数
 * 3、左组和右组marge,返回逆序对的个数
 *
 * [3,1,7,0,2]
 * 1、317 merge
 * 317
 * 3 17
 * 3 > 1 产生逆序对 31 p2++
 * 3 7 不产生逆序对 p1++
 *
 * 2、02 merge
 * 0 < 2 不产生逆序对 p1++
 * 3、31702 merge
 * 137 02
 * 1 > 0 产生逆序对  10 30 70 p2++
 * 137 2
 * 1 < 2 不产生逆序对 p1++
 * 37 2
 * 3 > 2 产生逆序对  32 72 p2++
 *
 * @Author : Darren
 * @Date : 2021 年 02 月 21 日 18:35:44
 * @since : 1.0
 */
public class J003_InversionPair {

    public static void main(String[] args) {
        int testTime = 500000;
        int maxSize = 100;
        int maxValue = 100;
        boolean succeed = true;
        for (int i = 0; i < testTime; i++) {
            int[] arr1 = generateRandomArray(maxSize, maxValue);
            int[] arr2 = copyArray(arr1);
            if (inversionPair(arr1) != inversionPair2(arr2)) {
                succeed = false;
                printArray(arr1);
                printArray(arr2);
                break;
            }
        }
        System.out.println(succeed ? "Nice!" : "Fucking fucked!");
    }


    public static int inversionPair(int[] arr){
        if (arr == null || arr.length < 2){
            return 0;
        }
        return process(arr, 0, arr.length - 1);
    }

    public static int inversionPair2(int[] arr){
        if (arr == null || arr.length < 2){
            return 0;
        }
        int res = 0;
        for (int i = 1; i < arr.length; i++) {
            for (int j = 0; j < i; j++) {
                res += arr[j] > arr[i] ? 1 : 0;
            }
        }
        return res;
    }


    private static int process(int[] arr, int l, int r) {
        //只有一个数,不产生逆序对
        if (l == r){
            return 0;
        }
        int mid = l + ((r - l) >> 1);
        //l …… mid的逆序对个数  + mid+1……r的逆序对个数 + l……r的逆序对个数
        return process(arr, l, mid)
        + process(arr, mid + 1, r)
        + marge(arr, l, mid, r);
    }

    private static int marge(int[] arr, int l, int mid, int r) {
        int[] help = new int[r - l + 1];
        int i = 0;
        int p1 = l;
        int p2 = mid + 1;
        int res = 0;
        while (p1 <= mid && p2 <= r){
            // 左组有多少个数比右组大,那么就产生多少对逆序对
            // 左组数小于右组的数,不产生逆序对,拷贝右组的数到help数组,右组下标++
            // 左组数大于右组的数,产生逆序对的个数为左组下标开始数有n个数比右组大(因为有序),拷贝左组的数到help数组,左组下标++
            res += arr[p1] <= arr[p2] ? 0 : (mid - p1 + 1);
            help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1 <= mid){
            help[i++] = arr[p1++];
        }
        while (p2 <= r){
            help[i++] = arr[p2++];
        }
        for (int i1 = 0; i1 < help.length; i1++) {
            arr[l + i1] = help[i1];
        }
        return res;
    }

    /**
     * 生成一个随机数组
     * @param maxSize
     * @param maxValue
     * @return
     */
    public static int[] generateRandomArray(int maxSize, int maxValue){
        //Math.random() [0,1)
        //Math.random() * N [0,N)
        //(int)(Math.random() * N) [0,N-1]
        int[] arrays = new int[(int) ((maxSize+1) * Math.random())];
        for (int i = 0; i < arrays.length; i++) {
            arrays[i] = (int) ((maxValue+1) * Math.random()) - (int)(maxValue * Math.random());
        }
        return arrays;
    }

    /**
     * 打印数组
     * @param arrays
     */
    public static void printArray(int[] arrays){
        if (arrays == null){
            return;
        }
        for (int i = 0; i < arrays.length; i++) {
            System.out.print(arrays[i] + " ");
        }
        System.out.println();
    }

    /**
     * 复制数组
     */
    public static int[] copyArray(int[] arr){
        if (arr == null){
            return null;
        }
        int[] res = new int[arr.length];
        for (int i = 0; i < arr.length; i++) {
            res[i] = arr[i];
        }
        return res;
    }

    /**
     * 判断两个数组是否相等
     * @param arr1
     * @param arr2
     * @return
     */
    public static boolean isArrayEqual(int[] arr1, int[] arr2){
        if ((arr1 == null && arr2 != null) || (arr1 != null && arr2 == null)){
            return false;
        }

        if (arr1 == null && arr2 == null){
            return true;
        }

        if (arr1.length != arr2.length){
            return false;
        }

        for (int i = 0; i < arr1.length; i++) {
            if (arr1[i] != arr2[i]){
                return false;
            }
        }
        return true;
    }

}

猜你喜欢

转载自blog.csdn.net/axin1240101543/article/details/114089946