publicstaticvoidmergeSort2(int[] arr){ if (arr == null || arr.length < 2) { return; } int N = arr.length; // 步长 int mergeSize = 1; while (mergeSize < N) { // log N // 当前左组的,第一个位置 int L = 0; while (L < N) { if (mergeSize >= N - L) { break; } int M = L + mergeSize - 1; int R = M + Math.min(mergeSize, N - M - 1); merge(arr, L, M, R); L = R + 1; } // 防止溢出 if (mergeSize > N / 2) { break; } mergeSize <<= 1; } }
publicstaticvoidmerge(int[] arr, int L, int M, int R){ int[] help = newint[R - L + 1]; int i = 0; int p1 = L; int p2 = M + 1; while (p1 <= M && p2 <= R) { help[i++] = arr[p1] <= arr[p2] ? arr[p1++] : arr[p2++]; } // 要么p1越界了,要么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]; } }
// arr[l..r]既要排好序,也要求小和返回 // 所有merge时,产生的小和,累加 // 左 排序 merge // 右 排序 merge // merge publicstaticintprocess(int[] arr, int l, int r){ if (l == r) { return0; } // l < r int mid = l + ((r - l) >> 1); return process(arr, l, mid) + process(arr, mid + 1, r) + merge(arr, l, mid, r); }
publicstaticintmerge(int[] arr, int l, int m, int r){ int[] help = newint[r - l + 1]; int i = 0; int p1 = l; int p2 = m + 1; int res = 0; while (p1 <= m && p2 <= r) { res += arr[p1] < arr[p2] ? (r - p2 + 1) * arr[p1] : 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 res; }
// arr[L..R]既要排好序,也要求逆序对数量返回 // 所有merge时,产生的逆序对数量,累加,返回 // 左 排序 merge并产生逆序对数量 // 右 排序 merge并产生逆序对数量 publicstaticintprocess(int[] arr, int l, int r){ if (l == r) { return0; } // l < r int mid = l + ((r - l) >> 1); return process(arr, l, mid) + process(arr, mid + 1, r) + merge(arr, l, mid, r); }
publicstaticintmerge(int[] arr, int L, int m, int r){ int[] help = newint[r - L + 1]; int i = help.length - 1; int p1 = m; int p2 = r; int res = 0; while (p1 >= L && p2 > m) { res += arr[p1] > arr[p2] ? (p2 - m) : 0; // 如果p1位置数大于p2位置,那么从m-p2都小于p1 help[i--] = arr[p1] > arr[p2] ? arr[p1--] : arr[p2--]; // 逆序合并 } while (p1 >= L) { help[i--] = arr[p1--]; } while (p2 > m) { help[i--] = arr[p2--]; } for (i = 0; i < help.length; i++) { arr[L + i] = help[i]; } return res; }
publicstaticintprocess(int[] arr, int l, int r){ if (l == r) { return0; } // l < r int mid = l + ((r - l) >> 1); return process(arr, l, mid) + process(arr, mid + 1, r) + merge(arr, l, mid, r); }
publicstaticintmerge(int[] arr, int L, int m, int r){ // [L....M] [M+1....R] int ans = 0;
// 首先统计数量 // 目前囊括进来的数,是从[M+1, windowR) int windowR = m + 1; for (int i = L; i <= m; i++) { while (windowR <= r && (long) arr[i] > (long) arr[windowR] * 2) { // 不需要回溯 windowR++; } ans += windowR - m - 1; }
// 合并两个排序数组 int[] help = newint[r - L + 1]; int i = 0; int p1 = L; int p2 = m + 1; 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; }
publicstaticintcountRangeSum(int[] nums, int lower, int upper){ if (nums == null || nums.length == 0) { return0; } // S(i, j) = S(0, j) - S(0, i-1), 用前缀和相减代替遍历求和 // 提前准备好前缀和数组 long[] sum = newlong[nums.length]; sum[0] = nums[0]; for (int i = 1; i < nums.length; i++) { sum[i] = sum[i - 1] + nums[i]; } return process(sum, 0, sum.length - 1, lower, upper); }
publicstaticintprocess(long[] sum, int L, int R, int lower, int upper){ if (L == R) { // 退出条件 return sum[L] >= lower && sum[L] <= upper ? 1 : 0; // 不能再merge直接判断 } int M = L + ((R - L) >> 1); return process(sum, L, M, lower, upper) + process(sum, M + 1, R, lower, upper) + merge(sum, L, M, R, lower, upper); }
publicstaticintmerge(long[] arr, int L, int M, int R, int lower, int upper){ int ans = 0; int windowL = L; int windowR = L; // [windowL, windowR) for (int i = M + 1; i <= R; i++) { // [M+1,R] long min = arr[i] - upper; // 最小前缀和 long max = arr[i] - lower; // 最大前缀和 while (windowR <= M && arr[windowR] <= max) { windowR++; // 满足条件的最大位置 } while (windowL <= M && arr[windowL] < min) { windowL++; // 满足条件的最小位置 } ans += windowR - windowL; // 满足条件的前缀和个数 } long[] help = newlong[R - L + 1]; int i = 0; int p1 = L; int p2 = M + 1; 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; }