寻找逆序对
持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
题目:在一个数组中,寻找前面的数比后面的数大的对数。
核心思想:利用归并排序的特性。我们学过归并排序的都知道,归并排序是先递归处理数组,处理完的数组两边就都是有序的,那么,我们可以利用这样一个特性,利用双指针的思想,如果在左边的指针所指的数大于右边指针所指的数,那么说明左边的指针到中间的所有的数,都和右指针当前所指的数构成逆序对,然后再累加求和即可。
步骤:
1.取中间数
2.计算左边区间的逆序对和右边区间的逆序对
3.利用归并排序特性计算边的数和右边的数共同所组成的逆序对
题目
/**
* 给定一个长度为 n 的整数数列,请你计算数列中的逆序对的数量。
*
* 逆序对的定义如下:对于数列的第 i 个和第 j 个元素,如果满足 i<j 且 a[i]>a[j],则其为一个逆序对;否则不是。
*
* 输入格式
* 第一行包含整数 n,表示数列的长度。
*
* 第二行包含 n 个整数,表示整个数列。
*
* 输出格式
* 输出一个整数,表示逆序对的个数。
*
* 数据范围
* 1≤n≤100000,
* 数列中的元素的取值范围 [1,109]。
*/
题解
public class ReserveOrderPairs {
public static void main(String[] args) {
int[] arr = new int[]{3, 1, 2, 4, 2};
System.out.println(mergeSortForPairs(0, arr.length-1,arr));
}
static long mergeSortForPairs(int l,int r,int[] arr){
if(l>=r) {
return 0;
}
//取中间数
int mid = l+r >> 1;
//计算左边区间的逆序对和右边区间的逆序对
long res = mergeSortForPairs(l,mid,arr) + mergeSortForPairs(mid+1,r,arr);
int k=0,i=l,j=mid+1;
int[] temp = new int[arr.length];
//归并排序的模板
while (i<=mid&&j<=r){
if(arr[i]<=arr[j]){
temp[k++] = arr[i++];
}else {
temp[k++] = arr[j++];
//这里统计了左边的数和右边的数共同所组成的逆序对
res+=(mid-i+1);
}
}
while (i<=mid) temp[k++] = arr[i++];
while (j<=r) temp[k++] = arr[j++];
for(i=l,k=0;i<=r;i++,k++) arr[i] = temp[k];
return res;
}
}
\