题目
* 面试题51:数组中的逆序对
* 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。
* 输入一个数组,求出这个数组中的逆序对的总数P。
* 并将P对1000000007取模的结果输出。 即输出P%1000000007
思路
1、暴力 ,时间复杂度O(n^2)
2、归并排序的思路 :时间复杂度O(nlogn)
* (1) 先将数组分成两半,递归分别计算左半边的逆序对数目leftCnt 和右半边的逆序对数目rightCnt
* (2)再计算合并之后新增的逆序对数目cnt
注意:
* left + right + cnt 有可能超过int,因此中间结果用long存储,最后再转化为int
代码
1 public class P51 { 2 // 归并排序 的变形 3 private long mergeSort(int[] datas, int[] copy, int start, int end){ 4 if(start == end) return 0; 5 int mid = (start + end)/2; 6 long leftCnt = mergeSort(datas, copy, start, mid)%1000000007;// 左边的逆序对数目 7 long rightCnt = mergeSort(datas, copy, mid+1, end)%1000000007; // 右边的逆序对数目 8 9 long cnt = 0; // 合并之后,新增的逆序对数目 10 int index = start; // copy数组的下标 11 int i = start; // 左半边 数组起始下标 12 int j = mid+1; // 右半边 数组起始下标 13 14 // 该变量记录当左半边某个数datas[i]插入copy数组中,右半边已经插入copy数组中的数目 15 int rightSmallICnt = 0; 16 17 // 合并数组,合并的时候计算逆序对数目 18 while(i<=mid && j<=end){ 19 if(datas[i]<=datas[j]){ 20 copy[index++] = datas[i]; 21 i++; 22 cnt += rightSmallICnt; 23 }else{ 24 copy[index++] = datas[j]; 25 j++; 26 rightSmallICnt++; // 记录右半边数组中右多少个元素 已经插入到copy数组中 27 } 28 } 29 if(i>mid){ 30 while(j<=end){ 31 copy[index++] = datas[j++]; 32 } 33 }else{ 34 while(i<=mid){ 35 copy[index++] = datas[i++]; 36 cnt += rightSmallICnt; 37 } 38 } 39 40 // 复制回原数组 41 for(int k=start;k<=end;++k) datas[k] = copy[k]; 42 return (leftCnt + rightCnt + cnt)%1000000007; 43 } 44 45 // 统计逆序对数目 46 public int InversePairs(int [] array) { 47 if(array==null || array.length<=1) return 0; // 对输入数据进行处理 48 int[] copy = new int[array.length]; // 辅助数组 49 return (int)mergeSort(array, copy, 0, array.length-1); 50 } 51 52 // 测试 53 public static void main(String[] args) { 54 int[] array = new int[]{5,6,7,8, 1, 2, 3, 4}; 55 int ans = new P51().InversePairs(array); 56 System.out.println(ans); 57 } 58 }
原文地址:https://www.cnblogs.com/chsobin/p/10585656.html
时间: 2024-11-05 22:40:08