剑指Offer51.数组中的逆序对

  • 题目:剑指Offer51.数组中的逆序对
    求一个给定数组的逆序对数;
    数组长度1<= n <= 50000;
  • 思路:
    最坏情况下,数组逆序,则逆序对数为(1 + 49999) * 49999 / 2 ≈12亿,因此用int存是可以的;

1.归并排序:时间O(nlogn),空间O(n)
分:将整个区间查找逆序对分成左右子区间的问题,整个区间[L,R]的逆序对数 = 左区间[L,mid]的逆序对数 + 右区间[mid,R]的逆序对数 + 左右区间各一个数的逆序对数;
治(合并阶段): 本质上是 合并两个排序数组 的过程,而每当遇到 左子数组当前元素 > 右子数组当前元素 时,意味着 「左子数组当前元素 至 末尾元素」 与 「右子数组当前元素」 构成了若干 「逆序对」

总的思路就是在归并排序的基础上,在合并两个排序左右区间之前,先求区间的逆序对数,再合并成一个排序区间;

class Solution {
    
    
public:
    vector<int> tmp;
    int merge_sort(vector<int>& nums, int l, int r) {
    
    //返回[l, r]区间内的逆序对数量
        if (l >= r) return 0;//当前区间已经被分成了仅剩一个数,因此逆序对数量为0
        
        //整个区间[l, r]的逆序对数量=逆序对的两个数均在左边[l, mid] + 均在右边[mid + 1, r] + 一个在左半区间一个在右半区间的数量
        int mid = l + r >> 1;
        int res = merge_sort(nums, l, mid) + merge_sort(nums, mid + 1, r);//分;先把均在左边,均在右边的加起来,后面再加一左一右的
        int i = l, j = mid + 1, k = 0;
        while (i <= mid && j <= r) {
    
    //若i>mid退出循环,则说明当前的q[j]太大了,在左半区间[l, mid]找不到>q[j]的数,因此相等于剩下的[j, r]的数量都为0,不用累计了;若j>r退出循环则表示对右半区间[mid + 1, r]的每一个数q[j]都在左半区间[l, mid]找到了>r它的数量
            if (nums[i] <= nums[j]) tmp[k++] = nums[i++];
            else {
    
    //一旦进来说明找到了左半区间[l, mid]中第一个大于q[j]的数,因为左右区间有序,因此[i, mid]数均>q[j],因此>q[j]的数量=mid - i + 1;
                res += mid - i + 1;//计以每个nums[j]为第二个数构成的的逆序对个数;
                tmp[k++] = nums[j++];
            }
        }
        //前面先对未归并的区间[l, mid],[mid + 1, r]累计逆序对数量res;其实[l, mid]和[mid + 1, r]已经有序了,之所以改变了数组顺序依然不影响逆序对,是因为逆序对的两个数均在左边[l, mid]和均在右边[mid + 1, r]的已经算完了,该层函数只需要在左右区间有序的基础上,求两边各一个数的逆序对,假设左区间有个数q[i]>右区间某个数q[j],则无论q[i]和q[j]在各自区间的哪个位置,都一定是一组逆序对 
        //再完成排序
        while (i <= mid) tmp[k++] = nums[i++];
        while (j <= r) tmp[k++] = nums[j++];
        for (i = l, k = 0; i <= r; ) nums[i++] = tmp[k++];
        
        return res;
    }
    int reversePairs(vector<int>& nums) {
    
    
        int n = nums.size();
        if (n < 2) return 0;
        tmp.resize(n);
        return merge_sort(nums, 0, n - 1);
    }
};

猜你喜欢

转载自blog.csdn.net/jiuri1005/article/details/114947022