求逆序对算法

#include <iostream>
#include <vector>

using namespace std;

// 归并排序并计算逆序对数量
long long mergeSort(vector<int>& nums, int left, int right) {
    if (left >= right) return 0;

    int mid = left + (right - left) / 2;

    // 分治递归
    long long count = mergeSort(nums, left, mid) + mergeSort(nums, mid + 1, right);

    // 归并合并
    vector<int> temp(right - left + 1);
    int i = left, j = mid + 1, k = 0;

    while (i <= mid && j <= right) {
        if (nums[i] <= nums[j])
            temp[k++] = nums[i++];
        else {
            temp[k++] = nums[j++];
            count += mid - i + 1;  // 统计逆序对数量
        }
    }

    while (i <= mid)
        temp[k++] = nums[i++];
    while (j <= right)
        temp[k++] = nums[j++];

    for (int p = 0; p < k; ++p)
        nums[left + p] = temp[p];

    return count;
}

int main() {
    int n;
    cin >> n;

    vector<int> nums(n);
    for (int i = 0; i < n; ++i)
        cin >> nums[i];

    // 调用归并排序函数并输出逆序对数量
    cout << mergeSort(nums, 0, n - 1) << endl;

    return 0;
}
  1. 首先定义了一个 mergeSort 函数,用于进行归并排序并计算逆序对的数量。
  2. 在 mergeSort 函数中,首先判断如果左指针大于等于右指针,则表示当前序列只有一个元素或者为空,不需要排序,直接返回逆序对数量为0。
  3. 计算中间位置的下标 mid,然后进行分治递归:
  • 递归调用 mergeSort 函数对左半部分进行排序,并将返回的逆序对数量累加到 count 中。
  • 递归调用 mergeSort 函数对右半部分进行排序,并将返回的逆序对数量累加到 count 中。
  • 创建一个临时数组 temp,大小为右指针减去左指针加1。
  • 使用三个指针 ijk 分别指向左半部分、右半部分和临时数组的位置,进行归并操作:
  • 当 nums[i] 小于等于 nums[j] 时,将 nums[i] 放入临时数组,并将指针 i 和 k 向后移动。
  • 当 nums[i] 大于 nums[j] 时,将 nums[j] 放入临时数组,并将指针 j 和 k 向后移动。此时,右半部分的元素都小于 nums[i],因此可以统计逆序对数量为 mid - i + 1,将该值累加到 count 中。(核心思想)
  • 将左半部分或右半部分剩余的元素依次放入临时数组。
  • 将临时数组中的元素复制回原始数组 nums 的相应位置。
  • 返回逆序对的数量 count
  • 在 main 函数中,首先读取数列的长度 n,然后创建一个大小为 n 的整数数组 nums,并依次读入数列的元素。
  • 调用 mergeSort 函数对数列进行排序并输出逆序对的数量。

Q:为什么可以统计统计逆序对数量为 mid - i + 1?

A:在归并排序的过程中,当合并左右两个有序数组时,如果左数组中的某个元素 nums[i] 大于右数组中的某个元素 nums[j],则说明左数组中 i 及其之后的元素都大于 nums[j]。因为左右数组都是有序的,所以可以推断左数组中 i 及其之后的元素与 nums[j] 构成逆序对。

在归并排序的合并过程中,当将 nums[j] 放入临时数组时,此时 i 到 mid 的元素都是满足逆序对条件的。因此,逆序对的数量就是 mid - i + 1

具体推导如下:

  • 在合并过程中,当 nums[i] > nums[j] 时,说明 nums[i] 及其之后的元素都大于 nums[j]
  • 假设 i 到 mid 的元素个数为 x,则逆序对的数量为 x
  • 因此,逆序对的数量为 mid - i + 1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值