题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

思想:

通过归并的思想,在不断归并过程中统计逆序对的个数

  • 在数组分裂的过程中,把left和right从第i个位置开始进行比较,哪个小就把它加入merged中,由于此时left和right是分别有序的,如果left[i]>right[j],证明left[i:]都大于right[j],此时的逆序对要加len(left)-i
  • 例如,left = [5, 7], right = [4, 6]
    1. i = 0, j = 0, 5>4, 此时5和7都是大于4的,逆序对加2-0=2, merged = [4]
    2. i = 0, j = 1, 5<6, 此时无逆序对,merged = [4, 5]
    3. i = 1, j = 1, 7>6, 逆序对加2-1=1,merged = [4, 5, 6]
    4. merged = [4, 5, 6, 7]

34 数组中的逆序对 - 图1

代码

  1. public class Solution {
  2. static int count=0;
  3. static int mod = (int) 1e9 + 7;
  4. public static void main(String[] args)
  5. {
  6. int[] arr = new int[] {1,2,3,4,5,6,7,0};
  7. mergeSort(arr,0,arr.length-1);
  8. System.out.println(count);
  9. }
  10. public static void mergeSort(int[] arr,int left,int right) {
  11. if(arr.length==0)return;
  12. if(left==right)return;
  13. int mid = left+(right-left)/2;
  14. mergeSort(arr,left,mid);
  15. mergeSort(arr,mid+1,right);
  16. merge(arr,left,mid,right);
  17. }
  18. public static void merge(int[] arr,int left,int mid,int right) {
  19. //用来存放归并的数
  20. int i=0;
  21. int[] temp = new int[right-left+1];
  22. //在归并的过程中统计逆序对
  23. int lp=left;
  24. int rp=mid+1;
  25. //逆序对个数
  26. while(lp<=mid&&rp<=right)
  27. {
  28. if(arr[lp]>arr[rp]) {
  29. count += (mid-lp+1);
  30. count = count%mod;
  31. temp[i++]=arr[rp++];
  32. }else
  33. {
  34. temp[i++]=arr[lp++];
  35. }
  36. }
  37. while(lp<=mid)
  38. {
  39. temp[i++]=arr[lp++];
  40. }
  41. while(rp<=right)
  42. {
  43. temp[i++]=arr[rp++];
  44. }
  45. for(int j=0;j<temp.length;j++)
  46. {
  47. arr[left++] = temp[j];
  48. }
  49. // return count;
  50. }
  51. }