数组中的逆序对
题目描述
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
输入描述:
题目保证输入的数组中没有的相同的数字
数据范围: 对于%50的数据,size<=10^4
对于%75的数据,size<=10^5
对于%100的数据,size<=2*10^5
示例1
输入
1,2,3,4,5,6,7,0
输出
7
方法一
最直观的一种方法就是顺序扫描整个数组,没扫描一个数字,就逐个比较该数字和他后面的数字的大小,看是否存在逆序对。但是这种方法的时间复杂度很大O(),这道题也表明了数据量很大,所以存在超时的可能。
public int InversePairs(int [] array) {
if(array == null || array.length <= 1) {
return 0;
}
int times = 0;
for (int i = 0; i < array.length; i++) {
for (int j = i + 1; j < array.length; j++) {
if(array[i] > array[j]) {
++times;
}
}
}
return times % 1000000007;
}
方法二
采用归并排序的思想:
如果对归并不太熟悉的可以看这篇文章:归并排序的理解和实现(Java)
把数据分成前后两个数组(递归分到每个数组仅有一个数据项),合并数组。
合并时,出现前面的数组值array[i]大于后面数组值array[j]时,则前面数组array[i]~array[mid]都是大于array[j]的,count += mid+1 - i (核心思想)
其次,测试用例输出结果比较大,对每次返回的count mod (1000000007)求余
public int times = 0;
public int InversePairs_2(int [] array) {
if(array != null && array.length > 0) {
mergeSortUp2Down(array, 0, array.length - 1);
}
return times;
}
public void mergeSortUp2Down(int[] elem, int start, int end) {
if(start >= end) {
return;
}
int mid = (start + end) / 2;
mergeSortUp2Down(elem, start, mid);
mergeSortUp2Down(elem, mid + 1, end);
merge(elem, start, mid, end);
}
public void merge(int[] elem, int start, int mid, int end) {
int[] temp = new int[end - start + 1];
int i = start;
int j = mid + 1;
int k = 0;
while(i <= mid && j <= end) {
if(elem[i] <= elem[j]) {
temp[k++] = elem[i++];
}
else {
temp[k++] = elem[j++];
times += mid - i + 1; // core code, calculate InversePairs
times %= 1000000007;
}
}
while(i <= mid) {
temp[k++] = elem[i++];
}
while(j <= end) {
temp[k++] = elem[j++];
}
for (i = 0; i < k; i++) {
elem[start + i] = temp[i];
}
temp = null;
}