剣はオファー51-配列C ++の逆順序ペアを参照します

債務返済質問3

タイトル説明

ここに画像の説明を挿入します

ソリューションマージソート

解決策を検討していなければ、現在、どのレベルでもマージと並べ替えを使用することは考えられません。
マージとソートのプロセスは、分解してからマージすることです。マージソート
ここに画像の説明を挿入します
は、分割統治のアイデアに基づいたソートです。
そして、治療の過程で逆順序対を数えることができます。
ここに画像の説明を挿入します
古いステッチは変です。怠惰な犬。
したがって、唯一の難しさは、ペアの数を逆の順序で数える方法です。
マージ関数で、左側と右側をマージするとき
に、左側の配列に右側の配列の数値aよりも大きい数値bがあることがわかった場合
、これはすべての数値と逆のペアを形成できます。 bから左配列の左端まで。
この時点で左側の配列はすでに順序付けられている(増加している)ため、添え字から境界までのすべての数値はaより大きくなります。
境界がmidaで、添え字がiの
場合、形成できる逆ペアの数は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;
    }
};

ここに画像の説明を挿入します
時間計算量O(NlogN)
空間計算量O(N):要素ごとに、個別のマージ関数がオンになってバックトラックするため、N * 1スペースを占有します。

おすすめ

転載: blog.csdn.net/qq_42883222/article/details/113007622