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