The sword refers to Offer 51- the reverse order pair in the array C++

Debt Repayment Question 3

Title description

Insert picture description here

Solution merge sort

If I haven't looked at the solution, I probably can't think of using merging and sorting at any level at my current level.
The process of merging and sorting is to decompose and then merge. Merge sorting
Insert picture description here
is sorting based on the idea of ​​divide and conquer.
And we can count the reverse order pairs in the process of treatment.
Insert picture description here
The old stitch is weird. Lazy dog.
So the only difficulty is how to count the number of pairs in reverse order.
In the merge function, when we merge the left and right sides,
if we find that there is a number b in the left array that is greater than a number a in the right array,
then this a can form your reverse pair with all the numbers from b to the left edge of the left array. .
Because the left array is already ordered (increasing) at this time, all numbers from the subscript to the boundary are greater than a.
If the boundary is mid a and the subscript is i
, the number of reverse pairs that can be formed is mid-i + 1.

class Solution {
    
    
public:
    int reversePairs(vector<int>& nums) {
    
    
        if(nums.size() < 2) return 0;
        int len = nums.size();
        vector<int> tmp(len);
        return mergeSort(nums, 0, len - 1, tmp);
    }
    int mergeSort(vector<int>& nums, int left, int right, vector<int> & tmp) {
    
    
        //递归结束条件
        if(left >= right) return 0;
        int mid = left + (right - left) / 2;
        int leftPairs = mergeSort(nums, left, mid, tmp);
        int rightPairs = mergeSort(nums, mid + 1, right, tmp);

        if(nums[mid] <= nums[mid + 1]) {
    
    
            //当我们调用归并之后,左右部分都已经排序好
            //只需要判断左边的最大值是否小于右边的最小值
            //如果小于就不存在跨左边和右边的逆序对了
            return leftPairs + rightPairs;
        }
        int crossPairs = merge(nums, left, mid, right, tmp);
        return leftPairs + rightPairs + crossPairs;
    }
    int merge(vector<int> & nums, int left, int mid, int right, vector<int>& tmp) {
    
    
        //归并排序开启条件:左右部分都已经升序排序好
        //进行左右的归并
        int count = 0;
        int i = left, j = mid + 1;//ij分别为左半部分和右半部分的起点
        int index = 0;
        while(i <= mid && j <= right) {
    
    
            if(nums[i] <= nums[j]) {
    
    
                tmp[index] = nums[i];
                index++;
                i++;
            }
            //当nums[i] > nums [j] 构成逆序对
            else {
    
    
                //比如[7,8] [5,6] i=0  j=2
                //nums[i]=7 nums[j]=5
                //5和7/8都能构成逆序对
                //所以j可以和nums[mid] ~ nums[i]之前的数字构成逆序对
                count += mid - i + 1;
                tmp[index] = nums[j];
                index++;
                j++;
            }
        }
        //多余部分的处理
        while(i <= mid) {
    
    
            tmp[index]=nums[i];
            index++;
            i++;
        }
        while(j <= right) {
    
    
            tmp[index]=nums[j];
            index++;
            j++;
        }
        //同步nums数组
        for(int i = left, j = 0; i <= right; i++,j++) nums[i] = tmp[j];
        return count;
    }
};

Insert picture description here
Time complexity O(NlogN)
Space complexity O(N): For each element, a separate merge function is enabled to backtrack, so it takes up N*1 space

Guess you like

Origin blog.csdn.net/qq_42883222/article/details/113007622