题目要求
算法思路
求逆序对的算法是利用了归并排序的思想,在归并排序的过程中会将序列分为两部分,此时逆序对可以分为三种情况:两个数都在左边的(设为s1)。两个数都在右边的(s2),一个数在左边一个数在右边的(s3)。
现在假设我们在归并排序的时候写的函数mergeSort(int[] arr, int l, int r)可以返回l到r区间中逆序对数量。那么s1=mergeSort(a, l, mid),s2=mergeSort(a, mid + 1, r);(s1是两个数都在左区间的逆序对个数,s2是两个数都在右区间的逆序对个数),s3(一个在左,一个在右,但显然要构成逆序对需要左区间的数小于右区间的数)很显然没有直观的答案。
那么核心问题就在于怎么求s3,以及怎么使我们的mergeSort(int[] arr, int l, int r)可以返回l到r区间中逆序对数量。
算法实现
怎么求s3?
if(array[i] <= array[j]){
temp[k++] = array[i++];
}else{
temp[k++] = array[j++];
}
if (a[i] <= a[j])
tem[k++] = a[i++];
else {
res += mid - i + 1;
tem[k++] = a[j++];
}
代码
package algorithm_;
/**
* @author TJU第一炼丹师
* @since 2024-02-26 17:23:39
*/
import java.util.*;
public class merge_Sort_788 {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int array[] = new int[n];
for (int i = 0; i < n; i++) {
array[i] = sc.nextInt();
}
long res = merge_Sort_788(array, 0, n - 1);
System.out.println(res);
}
public static long merge_Sort_788(int array[], int l, int r){
if(l >= r) return 0;
int mid = l + r >> 1;
//同一区间的逆序对
long res = merge_Sort_788(array, l ,mid) + merge_Sort_788(array, mid + 1, r);
int temp[] = new int[r - l + 1];
int k = 0, i = l, j = mid + 1;
while(i <= mid && j <= r){
if (array[i] <= array[j]){
temp[k++] = array[i++];
}else {
temp[k++] = array[j++];
//不同区间的逆序对
res += mid - i + 1;
}
}
while(i <= mid){temp[k ++ ] = array[i++];}
while(j <= r){temp[k ++ ] = array[j++];}
for (int m = l, t = 0; m <= r ; m++, t++) {
array[m] = temp[t];
}
//返回结果
return res;
}
}