剑指 Offer 51. 数组中的逆序对

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。 示例 1: 输入: [7,5,6,4] 输出: 5 限制:0 <= 数组长度 <= 50000

解题思路

1、直接使用暴力的方法 (遍历数组,不断比较后面的数字是否比当前的数字小,并计数) 会超时,复杂度 剑指 Offer 51. 数组中的逆序对 - 图1
2、可以借鉴归并排序,在数组合并过程中,进行元素大小比较的时候统计逆序对个数,由于归并排序算法复杂度为 剑指 Offer 51. 数组中的逆序对 - 图2 ,因此此算法复杂度也为 剑指 Offer 51. 数组中的逆序对 - 图3

如何统计逆序对个数?
当在归并数组 剑指 Offer 51. 数组中的逆序对 - 图4 ,区间 剑指 Offer 51. 数组中的逆序对 - 图5 和区间 剑指 Offer 51. 数组中的逆序对 - 图6 时 , ( 用下标 剑指 Offer 51. 数组中的逆序对 - 图7 指向前半区间, 剑指 Offer 51. 数组中的逆序对 - 图8 指向后半区间 )
剑指 Offer 51. 数组中的逆序对 - 图9 时,逆序个数加一,元素 剑指 Offer 51. 数组中的逆序对 - 图10 首先合并到有序数组中去,接下来 剑指 Offer 51. 数组中的逆序对 - 图11 的游标会往后移, 剑指 Offer 51. 数组中的逆序对 - 图12剑指 Offer 51. 数组中的逆序对 - 图13 进行比较…….
但是注意如果 剑指 Offer 51. 数组中的逆序对 - 图14 后面还有其他元素的化,因为 剑指 Offer 51. 数组中的逆序对 - 图15 已经被移到有序数组中去了,所以 剑指 Offer 51. 数组中的逆序对 - 图16 后面的元素没有机会再和它进行比较了,又由于数组的前半区间和后半区间是分别有序的,因为有:剑指 Offer 51. 数组中的逆序对 - 图17 ,所以必有
剑指 Offer 51. 数组中的逆序对 - 图18,从而如果仅仅加一会导致我们没有漏掉一些逆序个数。
为使不漏,应加上包括 剑指 Offer 51. 数组中的逆序对 - 图19 在内的其后面的前半区间元素个数,即 剑指 Offer 51. 数组中的逆序对 - 图20

代码实现

  1. class Solution {
  2. public:
  3. int res = 0;
  4. int reversePairs(vector<int>& nums) {
  5. int size = nums.size();
  6. int left = 0 ;
  7. int right = size - 1;
  8. vector<int> tempnums(size);
  9. divide(nums,tempnums,left,right);
  10. return res;
  11. }
  12. void divide(vector<int>& nums,vector<int>& tempnums,int left,int right) {
  13. if(left >= right )
  14. return;
  15. int mid = left + ((right - left) >> 1);
  16. divide(nums,tempnums,left,mid);
  17. divide(nums,tempnums,mid+1,right);
  18. //合并两个数组 merge(left,mid,right);
  19. int i = left, p = left;
  20. int j = mid + 1;
  21. while(i <= mid && j <= right) {
  22. if( nums[i] <= nums[j]){
  23. tempnums[p++] = nums[i++];
  24. }else{
  25. tempnums[p++] = nums[j++];
  26. /*
  27. nums[i] > nums[j],则 nums[i]后面的数都大于nums[j]
  28. 在这里的时候要统计上,否则nums[j]被合并到有序数组中去了,后面不会再被比较到
  29. */
  30. res = res + (mid - i + 1);
  31. }
  32. }
  33. while(i <= mid){
  34. tempnums[p++] = nums[i++];
  35. }
  36. while(j <= right){
  37. tempnums[p++] = nums[j++];
  38. }
  39. copy(tempnums.begin()+left, tempnums.begin()+right+1, nums.begin()+left);
  40. }
  41. };

**