计算右侧小于当前元素的个数(归并排序)

博客主要介绍了归并排序的解题思路,并给出了相关代码,归并排序是信息技术领域常用的排序算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

### 解题思路

归并排序

### 代码

class Solution {
public:
    vector<int> res;
    vector<pair<int,int>> temp;
    vector<pair<int,int>> pairIdx;
    void mergeSort (vector<pair<int,int>>& nums,int l,int r){
        if(l >= r) return;
        int mid = (l + r) >> 1;
        mergeSort(nums,l,mid);
        mergeSort(nums,mid+1,r);
        int p1=l,p2=mid+1,k=0;
        while(p1 <= mid && p2 <= r){
            if(nums[p1].first <= nums[p2].first){
                res[nums[p1].second] += p2-mid-1;
                temp[k++] = nums[p1++];
            }
            else temp[k++] = nums[p2++];
        }
        while(p1 <= mid){
            res[nums[p1].second] += p2-mid-1;
            temp[k++] = nums[p1++];
        }
        while(p2 <= r) temp[k++] = nums[p2++];
        for(int i = l,j=0;i <= r;i++,j++) nums[i] = temp[j];
    }
    vector<int> countSmaller(vector<int>& nums) {
        res = vector<int>(nums.size(),0);
        temp = vector<pair<int,int>>(nums.size());
        for(int i = 0; i < nums.size(); ++i) pairIdx.push_back({nums[i],i});
        mergeSort(pairIdx,0,nums.size()-1);
        return res;
    }
};

 

### 归并排序计算逆序对数量的方法 归并排序是一种基于分治法的高效排序算法,其核心思想是将数组分为两部分分别处理,再合并这两部分的结果。在合并的过程中可以统计逆序对的数量[^2]。 当使用归并排序计算逆序对时,在每次从右侧子数组取数放到最终位置时,左侧剩余未处理的部分都可以与当前右侧取出的数字构成一组或多组逆序对[^4]。具体来说: - 假设左半部分为 `left` 和右半部分为 `right`。 - 如果我们在合并过程中发现 `right[j] < left[i]`,那么意味着 `left[i..mid]` 中的所有元素都比 `right[j]` 大,从而形成了多个逆序对。 - 这些逆序对的数量可以通过简单的数学运算得出:`(mid - i + 1)`。 以下是完整的 C 实现代码示例: ```c #include <stdio.h> long long mergeAndCount(int *arr, int *tempArr, int left, int mid, int right) { int i = left; int j = mid + 1; int k = left; long long count = 0; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) { // 不形成逆序对的情况 tempArr[k++] = arr[i++]; } else { // 当右边小于左边时,形成逆序对 tempArr[k++] = arr[j++]; count += (mid - i + 1); // 统计逆序对数量 } } while (i <= mid) { // 将剩余的左半部分复制到临时数组 tempArr[k++] = arr[i++]; } while (j <= right) { // 将剩余的右半部分复制到临时数组 tempArr[k++] = arr[j++]; } for (int l = left; l <= right; ++l) { // 把临时数组的内容拷贝回原数组 arr[l] = tempArr[l]; } return count; } long long mergeSortAndCount(int *arr, int *tempArr, int left, int right) { long long inv_count = 0; if (left < right) { int mid = (left + right) / 2; inv_count += mergeSortAndCount(arr, tempArr, left, mid); inv_count += mergeSortAndCount(arr, tempArr, mid + 1, right); inv_count += mergeAndCount(arr, tempArr, left, mid, right); } return inv_count; } long long getInversionCount(int *arr, int n) { int *tempArr = (int *)malloc(sizeof(int) * n); long long result = mergeSortAndCount(arr, tempArr, 0, n - 1); free(tempArr); return result; } // 测试函数 void test() { int arr[] = {7, 5, 6, 4}; int n = sizeof(arr) / sizeof(arr[0]); printf("Number of Inversions are %lld\n", getInversionCount(arr, n)); } int main() { test(); return 0; } ``` #### 解释 上述程序实现了利用归并排序计算逆序对的功能: 1. **mergeAndCount 函数** 负责实际的合并操作以及逆序对的统计工作。 2. **mergeSortAndCount 函数** 是递归调用的核心逻辑,负责分割数组并对每一部分进行逆序对统计。 3. **getInversionCount 函数** 提供了一个接口用于初始化辅助数组,并启动整个流程。 此方法的时间复杂度为 O(n log n),空间复杂度为 O(n)[^3]。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值