You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

221 lines
6.4 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class16;
public class Code04_MergeRecord {
/*
* 腾讯原题
*
* 给定整数power给定一个数组arr给定一个数组reverse。含义如下
* arr的长度一定是2的power次方reverse中的每个值一定都在0~power范围。
* 例如power = 2, arr = {3, 1, 4, 2}reverse = {0, 1, 0, 2}
* 任何一个在前的数字可以和任何一个在后的数组,构成一对数。可能是升序关系、相等关系或者降序关系。
* 比如arr开始时有如下的降序对(3,1)、(3,2)、(4,2)一共3个。
* 接下来根据reverse对arr进行调整
* reverse[0] = 0, 表示在arr中划分每1(2的0次方)个数一组然后每个小组内部逆序那么arr变成
* [3,1,4,2]此时有3个逆序对。
* reverse[1] = 1, 表示在arr中划分每2(2的1次方)个数一组然后每个小组内部逆序那么arr变成
* [1,3,2,4]此时有1个逆序对
* reverse[2] = 0, 表示在arr中划分每1(2的0次方)个数一组然后每个小组内部逆序那么arr变成
* [1,3,2,4]此时有1个逆序对。
* reverse[3] = 2, 表示在arr中划分每4(2的2次方)个数一组然后每个小组内部逆序那么arr变成
* [4,2,3,1]此时有5个逆序对。
* 所以返回[3,1,1,5],表示每次调整之后的逆序对数量。
*
* 输入数据状况:
* power的范围[0,20]
* arr长度范围[1,10的7次方]
* reverse长度范围[1,10的6次方]
*
* */
public static int[] reversePair1(int[] originArr, int[] reverseArr, int power) {
int[] ans = new int[reverseArr.length];
for (int i = 0; i < reverseArr.length; i++) {
reverseArray(originArr, 1 << (reverseArr[i]));
ans[i] = countReversePair(originArr);
}
return ans;
}
public static void reverseArray(int[] originArr, int teamSize) {
if (teamSize < 2) {
return;
}
for (int i = 0; i < originArr.length; i += teamSize) {
reversePart(originArr, i, i + teamSize - 1);
}
}
public static void reversePart(int[] arr, int L, int R) {
while (L < R) {
int tmp = arr[L];
arr[L++] = arr[R];
arr[R--] = tmp;
}
}
public static int countReversePair(int[] originArr) {
int ans = 0;
for (int i = 0; i < originArr.length; i++) {
for (int j = i + 1; j < originArr.length; j++) {
if (originArr[i] > originArr[j]) {
ans++;
}
}
}
return ans;
}
public static int[] reversePair2(int[] originArr, int[] reverseArr, int power) {
int[] reverse = copyArray(originArr);
reversePart(reverse, 0, reverse.length - 1);
int[] recordDown = new int[power + 1];
int[] recordUp = new int[power + 1];
process(originArr, 0, originArr.length - 1, power, recordDown);
process(reverse, 0, reverse.length - 1, power, recordUp);
int[] ans = new int[reverseArr.length];
for (int i = 0; i < reverseArr.length; i++) {
int curPower = reverseArr[i];
for (int p = 1; p <= curPower; p++) {
int tmp = recordDown[p];
recordDown[p] = recordUp[p];
recordUp[p] = tmp;
}
for (int p = 1; p <= power; p++) {
ans[i] += recordDown[p];
}
}
return ans;
}
// originArr[L...R]完成排序!
// L...M左 M...R右 merge
// L...R 2的power次方
public static void process(int[] originArr, int L, int R, int power, int[] record) {
if (L == R) {
return;
}
int mid = L + ((R - L) >> 1);
process(originArr, L, mid, power - 1, record);
process(originArr, mid + 1, R, power - 1, record);
record[power] += merge(originArr, L, mid, R);
}
public static int merge(int[] arr, int L, int m, int r) {
int[] help = new int[r - L + 1];
int i = 0;
int p1 = L;
int p2 = m + 1;
int ans = 0;
while (p1 <= m && p2 <= r) {
ans += arr[p1] > arr[p2] ? (m - p1 + 1) : 0;
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;
}
// for test
public static int[] generateRandomOriginArray(int power, int value) {
int[] ans = new int[1 << power];
for (int i = 0; i < ans.length; i++) {
ans[i] = (int) (Math.random() * value);
}
return ans;
}
// for test
public static int[] generateRandomReverseArray(int len, int power) {
int[] ans = new int[len];
for (int i = 0; i < ans.length; i++) {
ans[i] = (int) (Math.random() * (power + 1));
}
return ans;
}
// for test
public static void printArray(int[] arr) {
System.out.println("arr size : " + arr.length);
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
}
// for test
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;
}
// for test
public static boolean isEqual(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;
}
public static void main(String[] args) {
int powerMax = 8;
int msizeMax = 10;
int value = 30;
int testTime = 50000;
System.out.println("test begin");
for (int i = 0; i < testTime; i++) {
int power = (int) (Math.random() * powerMax) + 1;
int msize = (int) (Math.random() * msizeMax) + 1;
int[] originArr = generateRandomOriginArray(power, value);
int[] originArr1 = copyArray(originArr);
int[] originArr2 = copyArray(originArr);
int[] reverseArr = generateRandomReverseArray(msize, power);
int[] reverseArr1 = copyArray(reverseArr);
int[] reverseArr2 = copyArray(reverseArr);
int[] ans1 = reversePair1(originArr1, reverseArr1, power);
int[] ans2 = reversePair2(originArr2, reverseArr2, power);
if (!isEqual(ans1, ans2)) {
System.out.println("Oops!");
}
}
System.out.println("test finish!");
powerMax = 20;
msizeMax = 1000000;
value = 1000;
int[] originArr = generateRandomOriginArray(powerMax, value);
int[] reverseArr = generateRandomReverseArray(msizeMax, powerMax);
// int[] ans1 = reversePair1(originArr1, reverseArr1, powerMax);
long start = System.currentTimeMillis();
reversePair2(originArr, reverseArr, powerMax);
long end = System.currentTimeMillis();
System.out.println("run time : " + (end - start) + " ms");
}
}