翻转对

package class04;

import java.util.Arrays;

/**
 * 翻转对
 * <p>
 * 在一个数组中,
 * 对于每个数num,求有多少个后面的数 * 2 依然<num,求总个数
 * <p>
 * https://leetcode-cn.com/problems/reverse-pairs
 * 给定一个数组nums,如果i < j且nums[i] > 2*nums[j]我们就将(i, j)称作一个重要翻转对。
 * 你需要返回给定数组中的重要翻转对的数量。
 * 举例:
 * 输入:[6, 3, 2]
 * 输出:1
 * 输入:[7, 3, 2]
 * 输出:2
 */
public class Code04_BiggerThanRightNumTwice {
    public static int biggerThanRightNumTwice(int[] arr) {
        if (arr == null || arr.length < 2) {
            return 0;
        }
        return process(arr, 0, arr.length - 1);
    }

    private static int process(int[] arr, int L, int R) {
        if (L == R) {
            return 0;
        }
        int M = L + ((R - L) >> 1);
        return process(arr, L, M) + process(arr, M + 1, R) + merge(arr, L, M, R);
    }

    //合并
    private static int merge(int[] arr, int L, int M, int R) {
        int ans = 0;
        //囊括在内的一共有几个数,[M+1, windowR)个。
        //符合条件的一共有几个数,[M+1, windowR)个。
        int windowR = M + 1;
        for (int i = L; i <= M; i++) {
            //需要强转成long类型,否则如arr[windowR] * 2溢出的话,执行结果和正确结果就会不同。
            //反例为当输入这个数组时:int[] arr0 = {2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647};
            //实际输出为15
            //正确输出为0
            while (windowR <= R && (long) arr[i] > (long) arr[windowR] * 2) {//只要windowR没有越界,并且arr[i]大于arr[windowR]的2倍
                windowR++;//windowR就++
            }
            //什么时候跳出循环?
            //当windowR越界,或者windowR来到第一个不符合要求的位置的时候。(也就是arr[windowR] * 2 >= arr[i]的时候)

            //计算符合条件的数字的个数,累加到ans上。
            ans += windowR - (M + 1);
        }
        int[] help = new int[R - L + 1];
        int p1 = L;
        int p2 = M + 1;
        int i = 0;
        while (p1 <= M && p2 <= R) {
            help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++];
        }
        while (p1 <= M) {
            help[i++] = arr[p1++];
        }
        while (p2 <= R) {
            help[i++] = arr[p2++];
        }
        for (i = 0; i < help.length; i++) {
            arr[L + i] = help[i];
        }
        return ans;
    }

    //test
    public static int biggerThanRightNumTwiceForTest(int[] arr) {
        int ans = 0;
        for (int i = 0; i < arr.length; i++) {
            for (int j = i + 1; j < arr.length; j++) {
                if ((long) arr[i] > (long) arr[j] << 1) {
                    ans++;
                }
            }
        }
        return ans;
    }

    public static int[] generatorRandomArray(int maxSize, int maxValue) {
        int[] arr = new int[(int) (Math.random() * maxSize) + 2];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * maxValue);
        }
        return arr;
    }

    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;
    }

    public static void main(String[] args) {
        int maxSize = 100;
        int maxValue = 100;
        int testTimes = 100000;
        System.out.println("test start!");
        for (int i = 0; i < testTimes; i++) {
            int[] arr0 = generatorRandomArray(maxSize, maxValue);
//            int[] arr0 = {2147483647, 2147483647, 2147483647, 2147483647, 2147483647, 2147483647};
            int[] arr1 = copyArray(arr0);
            int[] arr2 = copyArray(arr0);
            int num1 = biggerThanRightNumTwice(arr1);
            int num2 = biggerThanRightNumTwiceForTest(arr2);
            if (num1 != num2) {
                System.out.println("oops!");
                System.out.println("arr0 = " + Arrays.toString(arr0));
                System.out.println("num2 = " + num2);
                System.out.println("num1 = " + num1);
                break;
            }
        }
        System.out.println("test end!");
    }

}

 

posted @ 2022-11-08 22:32  TheFloorIsNotTooHot  阅读(27)  评论(0)    收藏  举报