求逆序数图解(分治)--算法学习
发布日期:2021-05-15 00:27:52 浏览次数:20 分类:精选文章

本文共 1494 字,大约阅读时间需要 4 分钟。

为了计算给定排列的逆序数,我们可以使用分治法结合归并排序的方法。这种方法的时间复杂度是O(n log n),非常适合处理较大的n值(如n ≤ 100000)。

分治法的步骤

  • 分割数组:将数组分成两半,左半和右半。
  • 递归计算:分别计算左半和右半的逆序数。
  • 合并计算:计算左半和右半之间形成的逆序对的数量。
  • 双指针法计算跨半逆序对

    假设左半和右半已经排好序,使用双指针从两端开始比较:

    • 左指针指向左半的开头,右指针指向右半的开头。
    • 比较左右指针所指的元素:
      • 如果左半的元素小于右半的元素,左指针前进。
      • 否则,右指针前进,并增加逆序对的数量。

    这种方法确保了每个元素只被访问一次,时间复杂度为O(n)。

    代码实现

    #include 
    #include
    using namespace std;
    long long sum = 0;
    void mergeSort(int* arr, int s, int e, int* temp) {
    if (s >= e) return;
    int mid = s + (e - s) / 2;
    mergeSort(arr, s, mid, temp);
    mergeSort(arr, mid + 1, e, temp);
    mergeAndCount(arr, s, mid, e, temp);
    }
    void mergeAndCount(int* arr, int s, int mid, int e, int* temp) {
    int p1 = s, p2 = mid + 1;
    while (p1 <= mid && p2 <= e) {
    if (arr[p1] < arr[p2]) {
    temp[index++] = arr[p1++];
    } else {
    sum += mid - p1 + 1;
    temp[index++] = arr[p2++];
    }
    }
    while (p1 <= mid) {
    temp[index++] = arr[p1++];
    }
    while (p2 <= e) {
    temp[index++] = arr[p2++];
    }
    }
    int main() {
    int n;
    vector
    a(n);
    for (int i = 0; i < n; ++i) {
    cin >> a[i];
    }
    int* temp = new int[n];
    mergeSort(a.data(), 0, n-1, temp);
    cout << sum << endl;
    delete[] temp;
    return 0;
    }

    代码解释

  • mergeSort函数:递归地将数组分成两半,调用自身进行排序,并在合并时使用mergeAndCount计算逆序对。
  • mergeAndCount函数:使用双指针法计算跨半的逆序对数量。左半和右半已排好序,通过比较左右指针所指元素的大小来确定逆序对的数量。
  • 主函数:读取输入,初始化数组,调用归并排序并计算逆序数,最后输出结果。
  • 这种方法不仅高效,还通过递归和迭代的结合,确保了代码的简洁和可维护性。

    上一篇:数字三角形(动态规划)--算法学习
    下一篇:输出前m大的数(分治)--算法学习

    发表评论

    最新留言

    不错!
    [***.144.177.141]2025年04月20日 09时59分45秒