Given an array nums
, we call(i, j)
an important reverse pair if i < j
andnums[i] > 2*nums[j]
.
You need to return the number of important reverse pairs in the given array.
Example1:
Input: [1,3,2,3,1] Output: 2
Example2:
Input: [2,4,3,5,1] Output: 3
Note:
50,000
.这题可以结合归并排序的思路,将问题拆分为两个子问题,在分别计算出两个子数组含有的重要反序组之后,再对跨两个子数组的重要反序组进行排序。假设两个子数组此时均为有序,则只需要用二分法的思路,找到满足条件的最远下标即可。代码如下:
public int reversePairs(int[] nums) {
if (nums == null) {
return 0;
}
long[] numsInLong = Arrays.stream(nums).asLongStream().toArray();
return reversePairs(numsInLong, 0, nums.length-1);
}
public int reversePairs(long[] nums, int left, int right) {
if (left >= right) {
return 0;
}
int mid = (left + right) / 2;
int leftReversePairs = reversePairs(nums, left, mid);
int rightReversePairs = reversePairs(nums, mid+1, right);
int count = 0;
int cur = mid;
while(cur >= left) {
int index = findRightMostIndex(nums, nums[cur], mid+1, right);
int tmpCount = index - mid - 1;
if (tmpCount == 0) {
break;
}
count += tmpCount;
cur--;
}
mergeSort(nums, left, right);
return count + leftReversePairs + rightReversePairs;
}
public void mergeSort(long[] nums, int left, int right) {
long[] copy = Arrays.copyOfRange(nums, left, right+1);
int mid = (left + right) / 2 - left;
int leftIndex = 0;
int rightIndex = mid + 1;
int index = left;
while (index <= right) {
if (rightIndex > right - left) {
nums[index++] = copy[leftIndex++];
} else if (leftIndex > mid) {
nums[index++] = copy[rightIndex++];
} else if (copy[leftIndex] <= copy[rightIndex]) {
nums[index++] = copy[leftIndex++];
} else {
nums[index++] = copy[rightIndex++];
}
}
}
public int findRightMostIndex(long[] nums, long num, int left, int right) {
while (left <= right) {
int mid = (left + right) / 2;
if (num > nums[mid] * 2) {
left = mid + 1;
} else {
right = mid - 1;
}
}
return left;
}
这里的一个优化点在于只复制一次完整的数组,减少不断初始化子数组备份的过程。