概述
题目来源 剑指offer
01 题目描述
在数组中如果前一个数字大于后一个数字,则称为这个数字组合组成一个逆序对。输入一个数组,求所有的逆序对的总数。
如 数组 {7,5,6,4} 则它的逆序对是 (7,5),(7,6),(7,4),(5,4) ,(6,4)总共有五个。
02 解法1
类似的题目,我们的第一反应都是,固定一个数,如7,然后从后面的数5,6,4中寻找是否有小于7的数,组成逆序对。这种方式实现的时间复杂度是 O(n^2)。
03 解法2
我们在学习算法的时候,学习过归并排序。如 7,5,6,4。先将数组拆分,然后再合并。合并的过程中对比排序。
初始化reverseCount = 0;
如下图将数组拆分
合并 7,5 6,4
我们发现 (7,5) , (6,4)可以组成一个逆序对, reverseCount+=2;
继续下面的合并,分析 左边=5,7 右边= 4,6
因为在这次合并的时候,组内已经是有序的了,所以组内右边是最大值。
对比7比,右边=4,6 的最大值6都大。所以此时我们可以计算reverseCount+=2(右面数值长度);将7放入合并数组。
然后判断5和6。此时6更大,将6放入合并数组。
对比 5和4,5比4大,所以可以构成逆序对, reverseCount+=1(右面剩余未合并的数组长度);
最后
结束 输出reverseCount;
时间复杂度 nlog(n)
04 总结&代码
1.用归并排序实现
2.在归并的过程中,从大到小归并,同时判断左边数组和右边数组的逆序对,如果左边的值大于右边的值,则逆序对 += 剩余待合并的右边的值。
public static long reverseCount(int[] arrays) { if (arrays == null || arrays.length == 0) { return 0; } int[] copyArray = new int[arrays.length]; return mergeSort(arrays, copyArray, 0, arrays.length - 1);}public static int mergeSort(int[] arrays, int[] copyArray, int start, int end) { if (start == end) { return 0; } int mid = (start + end) >> 1; int leftCount = mergeSort(arrays, copyArray, start, mid); int rightCount = mergeSort(arrays, copyArray, mid + 1, end); int count = merge(arrays, copyArray, start, end, mid); return (leftCount + rightCount + count) % (1000000007);}public static int merge(int[] arrays, int[] copyArray, int start, int end, int mid) { int copyEndIndex = end; int i = mid; int j = end; int count = 0; // merge while (i >= start && j >= mid + 1) { if (arrays[i] > arrays[j]) { copyArray[copyEndIndex--] = arrays[i--]; count += j - mid;// 如果左边数组大于右边,那么逆序对数量是 j-mid 即剩余长度 } else { copyArray[copyEndIndex--] = arrays[j--]; } } while (i >= start) { copyArray[copyEndIndex--] = arrays[i--]; } while (j >= mid + 1) { copyArray[copyEndIndex--] = arrays[j--]; } while (start <= end) { arrays[start] = copyArray[start]; start++; } return count;}
最后
以上就是凶狠大门为你收集整理的树状数组求逆序对_算法系列之-数组中的逆序对的全部内容,希望文章能够帮你解决树状数组求逆序对_算法系列之-数组中的逆序对所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复