归并排序其实代码很容易理解,在我们将数组中的元素从小到大排序的过程中,顺便解决了一个附加问题,即数组中的逆序对有多少个(即对于数组下标i, j
, 如果满足i < j 且 a[i] > a[j]
则称(i, j)为一个逆序对), 其实我们在排序的过程中,可以解决的不仅是逆序对的问题,由逆序对衍生的一系列问题(即对于数组下标i, j
, 如果满足i < j 且 a[i] > n * a[j]
), 我们都能解决,并且代码都是有套路的。
493. Reverse Pairs
这个问题就是归并排序衍生问题的一个例子, 我们观察一下如下AC代码:
class Solution {
private static final int WEIGHT = 2;
private int sum = 0;
public int reversePairs(int[] nums) {
if(nums == null || nums.length == 0 || nums.length == 1) {
return 0;
}
mergetSort(nums, 0, nums.length - 1);
return sum;
}
private void mergetSort(int[] nums, int start, int end) {
if (start >= end) {
return;
}
int mid = (start + end) >> 1;
mergetSort(nums, start, mid);
mergetSort(nums, mid + 1, end);
merge(nums, start, mid + 1, end);
}
private void merge(int[] nums, int left, int right, int end) {
if (right <= left) return;
int i = left;
int j = right;
int k = 0;
while(i < right && j <= end) {
if((long)nums[i] > (long)2 * nums[j]) {
sum += right - i;
j++;
} else {
i++;
}
}
i = left;
j = right;
int[] tmp = new int[end - left + 1];
for(; i < right && j <= end;) {
if (nums[i] < nums[j]) {
tmp[k++] = nums[i++];
} else {
tmp[k++] = nums[j++];
}
}
for(; i <right; i++) {
tmp[k++] = nums[i];
}
for(; j <= end; j++) {
tmp[k++] = nums[j];
}
for(i= 0; i < end - left + 1; i++) {
nums[i + left] = tmp[i];
}
}
}
其实完全是归并排序,只不过中间加上了代码:
while(i < right && j <= end) {
if((long)nums[i] > (long)2 * nums[j]) {
sum += right - i;
j++;
} else {
i++;
}
}
其中的2可以换成任意的n