题目:
分析:
- 解法一: 暴力解法, 遍历所有的数对, 找到逆序对, 需要两重for循环, 一定会超时
- 解法二: 归并排序的思想
- 如果我们将数组分成两半, 我们在每一半中各找一个数字, 判断是否为逆序对, 再根据归并的思想, 再将一半数组分半, 判断是否为逆序对, 直到数组只有一个元素或一个元素也没有, 此时也不具有逆序对了
- 如果我们再对数组进行归并排序, 归并排序有一个结论就是: 如果是升序排序, 当前的cur1前面的数字和cur2前面的数字一定是都小于cur1和cur2的
- 策略一: 升序排序, 根据后面一半的数字cur2, 找出前面一半有多少个数字比它大
如果这时nums[cur1] > nums[cur2] , 说明cur1前面的数字都不可能比cur2大, 而cur1后面的数字包括cur1都是比cur2大的, 所以我们可以利用升序排序, 轻松的找到多个逆序对, 即cur1到mid, 然后由于是升序, 需要将cur2放在tmp数组中, cur2++
如果这时nums[cur1] <= nums[cur2], 说明cur1前面的数字包括cur1都不可能比cur2大, 后面的数我们还不知道, 所以只需将cur1++即可, 并在这之前根据归并排序的规则, 将此数放在tmp数组中 - 同样, 如果是降序排序, 当前的cur1前面的数字和cur2前面的数字一定是都大于cur1和cur2的
- 策略二: 降序排序, 根据前面一半的数字cur1, 找出后面一半有多少个数字比它小
如果这时nums[cur1] > nums[cur2] , 说明cur2后面的数字包括cur2都比cur1小, 所以我们可以利用降序排序, 轻松的找到多个逆序对, 即cur2到right, 然后需要将cur1放在tmp数组中, cur1++
如果这时nums[cur1] <= nums[cur2], 说明cur2前面的数字包括cur2都比cur1大,, 而cur2后面的数字还不知道, 然后由于是降序, 需要将cur2放在tmp数组中, cur2++
代码:
java
class Solution {
int[] tmp;
public int reversePairs(int[] record) {
tmp = new int[record.length];
return mergeSort(record, 0, record.length - 1);
}
public int mergeSort(int[] nums, int left, int right) {
if (left >= right)
return 0;
int ret = 0;
int mid = left + ((right - left) >> 1);
ret += mergeSort(nums, left, mid);
ret += mergeSort(nums, mid + 1, right);
int cur1 = left;
int cur2 = mid + 1;
int i = 0;
while (cur1 <= mid && cur2 <= right) {
if (nums[cur1] <= nums[cur2]) {
tmp[i++] = nums[cur1++];
} else {
ret += mid - cur1 + 1;
tmp[i++] = nums[cur2++];
}
}
while (cur1 <= mid) {
tmp[i++] = nums[cur1++];
}
while (cur2 <= right) {
tmp[i++] = nums[cur2++];
}
for (int j = left; j <= right; j++) {
nums[j] = tmp[j - left];
}
return ret;
}
}