求数组逆序对个数

题目描述

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

class Solution {
public:
    int InversePairs(vector<int> data) {
        return mergesort(data,0,(int)data.size());
    }

    int merge(vector<int> &data, int s,int mid,int e){
        auto it = data.begin();
        vector<int> a1(it+s, it+mid); a1.push_back(INT_MAX);
        vector<int> a2(it+mid, it+e); a2.push_back(INT_MAX); // 归并排序中加入哨兵
        int i1=0,i2=0,i=s;
        int count=0;
        while(i<e){
            if(a1[i1]<=a2[i2]){ // 注意这里必须是<=,因为2数相等不算逆序
                data[i] = a1[i1];
                i1++;
            }else{
                data[i] = a2[i2];
                i2++;
                count += mid-s-i1; // 逆序个数为还没进入data的i1的个数
            }
            i++;
        }
        return count;

    }

    int mergesort(vector<int> &data, int s, int e){
        if (s+1>=e)
            return 0;
        int mid = (e-s)/2+s;
        int c1 = mergesort(data, s, mid);
        int c2 = mergesort(data, mid, e);
        return merge(data,s,mid,e)+c1+c2;
    }
};

对于数组 [6, 5, 4, 3, 2, 1],逆序对为15个。

总的思路就是归并排序的思路,求一个数组的逆序,包括3部分,一是数组前半部分的逆序,二是数组后半部分的逆序,三是一个在前,一个在后形成的逆序。

我们发现,一和二是原问题的子问题,因此可以用递归描述;

三是一个新的问题:即数组a和数组b中各出一个元素,问能形成多少对逆序。在a和b无序的情况下,需要进行n*n次比较(假设a和b的元素个数都为n),

但a和b有序的情况下,只需要进行2n次比较,并且在比较完成后将a和b归并为一个有序序列。因此对于该问题,在求解完成后得到的数组一定是有序的。



### C++算法实现计算数组中的逆序对数量 为了计算给定数组中的逆序对数目,可以采用多种方法。一种高效的方式是基于归并排序的思想来设计算法。该算法的时间复杂度为O(n log n),这比暴力解法要好得多。 #### 归并排序变种逆序对 通过修改标准的归并排序过程,在每次合并两个有序子序列的同时统计跨过这两个子序列边界的逆序对的数量: ```cpp #include <vector> using namespace std; long long merge_and_count(vector<int>& nums, vector<int>& temp, int left, int mid, int right) { int i = left; int j = mid + 1; int k = left; long long inversions = 0; while (i <= mid && j <= right) { if (nums[i] <= nums[j]) { temp[k++] = nums[i++]; } else { // 当前右边元素小于左边,则存在(mid-i+1)个逆序对 temp[k++] = nums[j++]; inversions += static_cast<long long>(mid - i + 1); } } while (i <= mid) { temp[k++] = nums[i++]; } while (j <= right) { temp[k++] = nums[j++]; } copy(temp.begin() + left, temp.begin() + right + 1, nums.begin() + left); return inversions; } long long merge_sort_and_count_inversions(vector<int>& nums, vector<int>& temp, int left, int right) { if (left >= right) return 0; int mid = left + (right - left) / 2; long long count = 0; count += merge_sort_and_count_inversions(nums, temp, left, mid)[^3]; count += merge_sort_and_count_inversions(nums, temp, mid + 1, right); count += merge_and_count(nums, temp, left, mid, right); return count; } long long countInversions(const vector<int>& nums) { vector<int> temp(nums.size()); return merge_sort_and_count_inversions(const_cast<vector<int>&>(nums), temp, 0, nums.size() - 1); } ``` 此代码片段展示了如何利用改进后的归并排序来有效地找出所有的逆序对,并返回其总数目。`countInversions()` 函数接收一个整型向量作为输入参数,并调用辅助函数完成实际的工作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值