0
点赞
收藏
分享

微信扫一扫

剑指 Offer 51. 数组中的逆序对(困难)

窗外路过了谁 2022-05-06 阅读 79

一、题目

1、题目描述

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例1:

输入: [7,5,6,4]
输出: 5

2、基础框架

class Solution {
public:
    int reversePairs(vector<int>& nums) {

    }
};

3、原题链接

剑指 Offer 51. 数组中的逆序对

二、解题报告

1、思路分析

  (1)利用 归并排序 在合并时数组部分有序的特征,合并时分为左组和右组,同组之间不考虑逆序对,因为在上一层合并的过程中已经考虑过了
  (2)小技巧:合并时的左组和右组,从右往左合并,当右组的当前元素已经小于左组当前元素时,那么对于左组当前元素,逆序对的个数就是 p2 - mid + 1 - 1 = p2 - mid

2、时间复杂度

O ( n l o g n ) O(nlogn) O(nlogn)

3、代码详解

class Solution {
private:
    int merge(vector<int> &arr, int l, int mid, int r) {
        vector<int> help(r - l + 1);
        int p1 = mid;
        int p2 = r;
        int ind = r - l;
        int cnt = 0;

        //合并时从右往左合并,能快速定位到比当前左组元素小的右组元素个数
        while (p1 >= l && p2 > mid) {
            cnt += arr[p1] > arr[p2] ? p2 - mid : 0;
            help[ind--] = arr[p1] > arr[p2] ? arr[p1--] : arr[p2--];
        }

        while (p1 >= l) {
            help[ind--] = arr[p1--];
        }

        while (p2 > mid) {
            help[ind--] = arr[p2--];
        }

        for (int i = 0; i < help.size(); i++) {
            arr[l + i] = help[i];
        }

        return cnt;
        
    }

    int process(vector<int> &nums, int l, int r) {
        if (l == r) return 0;

        int mid = l + ((r - l) >> 1);
        int left = process(nums, l, mid);
        int right = process(nums, mid + 1, r);
        int mergeAns = merge(nums, l, mid, r);
        return left + right + mergeAns;
    }
public:
    //目标:求每个数字右边比它小的数字个数
    int reversePairs(vector<int>& nums) {
        if (nums.size() < 2) return 0;

        return process(nums, 0, nums.size() - 1);
    }
};
举报

相关推荐

0 条评论