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!");
}
}