剑指offer 51 - 数组中的逆序对

1 题目

https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof

2 题意

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

示例 1:
输入: [7,5,6,4]
输出: 5

3 思路

author's blog == http://www.cnblogs.com/toulanboy/

3.1 基础想法

(1)本题要求的是逆序对,逆序对的定义题面已经给出。
(2)而求逆序对的常见解法是借助归并排序来实现,更具体是借助他的merge过程

3.2 归并排序求逆序对

(1)归并逻辑

我们知道,归并排序实际上分治的思想,归并排序的逻辑如下:

  • 其先将数组不断细分,最后细分到每个数组只有1个元素,那么这个只包含1个元素数组中就是有序的。
  • 然后将两个有序的长度为1的数组依次合并为长度为2的有序数组,后面合并过程就是依次类推,2合44合8,...,n/2合n

(2)Merge过程

值得注意的是:在上述的合并过程中,我们是可以得到其逆序对个数的?

举个例子来说明合并过程:
数组A: 11 22 33 44
数组B: 12 20 55 66
数组A和数组B合并为一个数组。
正常做法是:分别用2个指针p1, p2指向A和B的第一个元素。然后进行两两对比,谁小谁下来放进新数组。

进一步地,我们可以利用这个合并过程。若在上述例子中,p1指向22, p2指向20。那么可知p1 > p2,,们可知逆序对(22, 20),而且还可知道p1后面的数,都比20要大,所以可得到逆序对(33, 20)、(44, 20)。 故可得到的逆序对个数是p1后面剩余的元素个数。

通过合并过程累加,就可以得到整个序列的逆序对。

可能有同学想问:上述合并,只是得到了两个相对位置数组的逆序对,但逆序对个数还应该包括这个位置相对其他位置的逆序对,这部分是如何统计上去的?

答:实际上,上述两个相对位置数组合并为1个大数组后,他必然会经历和前面大数组、后面大数组的过程,所以他前面的元素、他后面的元素相对他的逆序对个数也会被统计到的。

4 代码

//author's blog == http://www.cnblogs.com/toulanboy/
class Solution {
public:
    int ans = 0;
    vector<int> temp;//辅助数组,用来存储新的有序数组
    void fenzhi(vector<int>& nums, int left, int right){
        if(left >= right){
            return;
        }
        int mid = (left+right) >> 1;
        fenzhi(nums, left, mid);//拆分,得到左边
        fenzhi(nums, mid+1, right);//拆分,得到右边
        merge(nums, left, mid, right);//左右合并
    }
    void merge(vector<int>& nums, int left, int mid, int right){
        int p1 = left;
        int p2 = mid+1;
        temp.clear();
        while(p1 <= mid && p2 <= right){
            if(nums[p1] <= nums[p2]){
                temp.push_back(nums[p1]);
                p1++;
            }
            else{
                temp.push_back(nums[p2]);
                p2++;
                ans += (mid-p1+1);
            }
        }
        while(p1 <= mid){
            temp.push_back(nums[p1]);
            p1++;
        }
        while(p2 <= right){
            temp.push_back(nums[p2]);
            p2++;
        }
        for(int i=0; i<temp.size(); ++i){
            nums[left+i] = temp[i];
        }
    }

    int reversePairs(vector<int>& nums) {
        fenzhi(nums, 0, nums.size()-1);
        return ans;
    }
};
posted @ 2020-09-14 19:28  偷懒人  阅读(135)  评论(0编辑  收藏  举报