题目描述:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007
解题思路:
- 顺序扫描数组的话,则每个数需要和n个数进行比较,时间复杂度为O(n~2),尝试更快的算法
- 只是相邻两个数进行比较,将数组拆分成子数组,知道拆分一个个数组长度为1的小数组,
- 然后两两归并,若前面那个数大于后面那个数,则逆序对加1,同时将这两数按从小到大排序,以免在后面重复统计
- 再继续归并成,最终归并成一个大数组
- 对于两个子数组归并的过程中,左右两个指针分别指向左右两个数组的最后一个元素,若左指针指向的元素大于右指针指向的元素,则逆序对加上右指针元素位置-mid的个数,同时将这个较大的元素放入辅助数组中,若小于,则逆序对个数不增加,只把右指针指向的那个元素放到辅助数组中
- 总结:先把数组分隔成子数组,统计出子数组内部的逆序对的数目,然后再统计出两个相邻子数组之间的逆序对的数目,在统计逆序对的过程中,还需要对数组进行排序
根据上述分析,其实该思路是基于归并排序,时间复杂度为O(nlogn),空间复杂度为O(n).
private long cnt = 0; private int[] temp; public int InversePairs(int [] array) { int low = 0; int high = array.length-1; temp = new int[high-low+1]; MergeSort(array,low,high); return (int)(cnt%1000000007); } public void MergeSort(int[] a,int low,int high){ if(low<high){ int mid = (high+low)/2; MergeSort(a,low,mid); MergeSort(a,mid+1,high); merge(a,low,mid,high); } } public void merge(int[] a,int low,int mid,int high){ int k = high; int left = mid; int right = high; while(left>=low&&right>=mid+1){ if(a[left]>a[right]){ cnt+=right-mid; temp[k--] = a[left--]; } else{ temp[k--] = a[right--]; } } while(left>=low){ temp[k--] = a[left--]; } while(right>=mid+1) temp[k--] = a[right--]; for(int i = low;i<=high;i++) a[i] = temp[i]; }