Sword refers to Offer51. The reverse pair in the array

  • Topic: Sword refers to Offer51. Reversed pairs in an array
    Find the reversed logarithm of a given array;
    array length 1<= n <= 50000;
  • Idea: In the
    worst case, if the array is reversed, the reverse logarithm is (1 + 49999) * 49999/2 ≈1.2 billion, so it is possible to use int to save;

1. Merge sorting: time O(nlogn), space O(n)
points: divide the entire interval into the left and right sub-intervals to find inverse pairs, the inverse logarithm of the entire interval [L, R] = left interval [L, mid] The inverse logarithm of + the inverse logarithm of the right interval [mid, R] + the inverse logarithm of a number in each of the left and right intervals;
cure (merging stage): essentially the process of merging two sorted arrays, and whenever you encounter the left When the current element of the sub-array> the current element of the right sub-array, it means that "the current element of the left sub-array to the end element" and "the current element of the right sub-array" form a number of "reverse pairs"

The general idea is to find the reverse logarithm of the interval before merging the two sorted left and right intervals on the basis of merge sorting, and then merge into a sorting interval;

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);
    }
};

Guess you like

Origin blog.csdn.net/jiuri1005/article/details/114947022
Recommended