描述
剑指offer JZ51 数组中的逆序对
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P mod 1000000007
方法:归并排序分治
思路:
利用归并排序统计逆序对
具体实现及注释:
java
public class Solution {
//归并排序中的临时数组
int[] temp;
//目标数组
int[] nums;
int mod = 1000000007;
public int InversePairs (int[] nums) {
if (nums == null || nums.length == 0) return 0;
this.nums = nums;
temp = new int[nums.length];
return mergeSort(0, nums.length-1);
}
int mergeSort(int head, int tail) {
//退出递归的条件
if (head == tail) return 0;
int mid = (head + tail) / 2;
//左边递归
int leftNum = mergeSort(head, mid);
//右边递归
int rightNum = mergeSort(mid+1, tail);
//向临时数组中复制元素
for (int i = head; i <= tail; i++) {
temp[i] = nums[i];
}
int left = head;
int right = mid + 1;
int count = 0;
//在归并排序中,需要将左边的元素和右边的元素比较,谁小谁先回到原数组。但是此题还要统计逆序对。因为左半部分和右半部分的元素已经有序,如果在遍历过程中,右半部分的元素比左半部分的元素更小,说明出现了逆序对。此时左半部分的元素为left,在左半部分中比left还大的元素个数为mid-left,右半部分的right比left小,肯定比剩下mid-left个元素都小,所以逆序对有mid-left+1个。
for (int i = head; i <= tail; i++) {
//这种情况是左半部分的元素全部入队,此时右半部分的元素正常入队即可
if (left == mid+1) nums[i] = temp[right++];
//需要左半部分元素一次入队的情况
else if (right == tail+1 || temp[left] < temp[right]) nums[i] = temp[left++];
//出现逆序对
else {
nums[i] = temp[right++];
count = (count + mid - left + 1) % mod;
}
}
return (leftNum + rightNum + count) % mod;
}
}