树状数组求逆序对_算法系列之-数组中的逆序对

题目来源 剑指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;

如下图将数组拆分

4ea933626300d4a9493760c2ea7806f4.png

合并 7,5 6,4

9a62f2b7c8783dcc9e56407e94c97ea9.png

我们发现 (7,5) , (6,4)可以组成一个逆序对, reverseCount+=2;

继续下面的合并,分析 左边=5,7 右边= 4,6

383417ea2a88d30a1fded1e35c15c452.png

因为在这次合并的时候,组内已经是有序的了,所以组内右边是最大值。

对比7比,右边=4,6 的最大值6都大。所以此时我们可以计算reverseCount+=2(右面数值长度);将7放入合并数组。

cf70a6b0ad2a93de913efe19e57c1df3.png

然后判断5和6。此时6更大,将6放入合并数组。

b5d01eeda98ceffd125258ebf7da8150.png

对比 5和4,5比4大,所以可以构成逆序对, reverseCount+=1(右面剩余未合并的数组长度);

e96f27aec5b1aeae2ed2ad0185247a94.png

最后

3d637fdc4e64cb3c672e807dcf0aa11a.png

结束 输出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;}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值