Sword refers to offer (C++)-JZ51: reverse order pair in array (algorithm - sorting)

Author: Zhai Tianbao Steven
Copyright statement: The copyright belongs to the author. For commercial reprint, please contact the author for authorization. For non-commercial reprint, please indicate the source

Title description:

Two numbers in the array, if the previous number is greater than the following number, the two numbers form a reverse pair. Enter an array and find the total number P of reversed pairs in this array. And output the result of P modulo 1000000007. That is, the output P mod 1000000007
data range: For 50% of the data, size≤104
For 100% of the data, size≤105

The values ​​of all numbers in the array satisfy 0≤val≤109

Requirements: space complexity O(n), time complexity O(nlogn)

Example:

enter:

[1,2,3,4,5,6,7,0]

return value:

7

Problem-solving ideas:

The conventional solution to this question is the violent method, but this question requires a complexity of nlogn, so it can be solved by merge sort.

  1. Write a merge sort normally.
  2. In the process of merging and sorting combined sorting, the data of the two subintervals will be compared in turn to reconstruct the new order; at this time, if the value A on the left is greater than the value B on the right, then you can directly transfer the number of data from A to the middle position C Add directly. Because the subintervals have been sorted, since A is greater than B, all the data between A and C must also be greater than B, so a reverse order pair can be formed.
  3. In this way, the time complexity meets the requirements of the topic.

Test code:

class Solution {
public:
    int mod = 1000000007;
    // 归并排序
    int mergeSort(vector<int>& data, int left, int right){
        // 停止
        if(left >= right)
            return 0;
        // 中间位
        int mid = (left + right) / 2;
        // 拆分合并,累加逆序对数量
        int count = mergeSort(data, left, mid) + mergeSort(data, mid + 1, right);
        count %= mod;
        // 排序
        int i = left, j = mid + 1;
        vector<int> temp(data);
        for(int t = left; t <= right; ++t){
            // i如果到了mid+1,说明左子区间遍历完毕,后续直接取右区间数据即可
            if(i == mid + 1){
                data[t] = temp[j];
                j++;
            }
            // j如果到了right+1,说明右子区间遍历完毕,后续直接取左区间数据即可
            // 如果左侧值小于右侧值,不符合逆序对,正常排序即可
            else if(j == right + 1 || temp[i] <= temp[j]){
                data[t] = temp[i];
                i++;
            }
            // 如果左侧值大于右侧值,说明左侧当前位置到左子区间结束的数值,都大于该右侧值,直接计算数量:mid-i+1;然后正常排序
            // 这样操作降低了时间复杂度
            else{
                data[t] = temp[j];
                j++;
                count += mid - i + 1;
            }
        }
        return count % mod;
    }
    // 逆序对
    int InversePairs(vector<int>& nums) {
        int size = static_cast<int>(nums.size());
        int count = mergeSort(nums, 0, size - 1);
        return count;
    }
};

Guess you like

Origin blog.csdn.net/zhaitianbao/article/details/131371768