【C++算法】48.分治_归并_数组中的逆序对

文章目录


题目链接:

剑指 Offer 51. 数组中的逆序对


题目描述:


解法

解法一:暴力解法:暴力枚举

两层for循环

本题不能用,用了会超时。
解法二:

归并排序


C++ 算法代码:

cpp 复制代码
class Solution 
{
    int tmp[50010]; // 用于在归并过程中临时存储排序后的元素
    public:
    int reversePairs(vector<int>& nums) 
    {
        return mergeSort(nums, 0, nums.size() - 1); //返回逆序对的数量
    }
    int mergeSort(vector<int>& nums, int left, int right)
    {
        if(left >= right) return 0; // 基本情况:区间内只有一个元素或为空,没有逆序对
        int ret = 0; // 用于存储当前区间内的逆序对数量
        // 1. 找中间点,将数组分成两部分
        int mid = (left + right) >> 1; // 使用位运算 (left + right) / 2 提高效率
        // [left, mid][mid + 1, right]
        // 2. 递归地对左右两个子区间进行排序,并计算逆序对数量
        // 左边的个数 + 排序 + 右边的个数 + 排序 
        v // 右半部分的逆序对
        // 3. 计算跨越左右两个子区间的逆序对数量
        // cur1指向第一个子数组的当前元素
        // cur2指向第二个子数组的当前元素
        // i指向临时数组的当前位置
        int cur1 = left, cur2 = mid + 1, i = 0;
        // 当两个子数组都还有元素时,比较并处理
        while(cur1 <= mid && cur2 <= right) // 升序的时候
        {
            if(nums[cur1] <= nums[cur2])
            {
                tmp[i++] = nums[cur1++];
            }
            else
            {
                // 当 nums[cur1] > nums[cur2] 时,说明 cur1 到 mid 之间的所有元素都大于 nums[cur2]
                // 因此,逆序对的数量为 mid - cur1 + 1
                ret += mid - cur1 + 1;
                tmp[i++] = nums[cur2++];
            }
        }
        // 4. 处理一下排序
        while(cur1 <= mid) tmp[i++] = nums[cur1++];
        while(cur2 <= right) tmp[i++] = nums[cur2++];
        // 5. 将临时数组中的合并结果复制回原数组的对应位置
        for(int j = left; j <= right; j++)
            nums[j] = tmp[j - left];

        return ret; // 返回当前区间内的逆序对总数
    }
};

图解

例如:nums = [9, 7, 5, 4, 6]

  1. mergeSort(nums, 0, nums.size() - 1);->mergeSort(nums, 0, 4);

    ret = 0;mid = 2;

    ret += mergeSort(nums, left, mid);->ret += mergeSort(nums, 0, 2);

  1. mergeSort(nums, 0, 2);

    ret = 0;mid = 1;

    ret += mergeSort(nums, left, mid);->ret += mergeSort(nums, 0, 1);

  1. mergeSort(nums, 0, 1);

    ret = 0;mid = 0;

    ret += mergeSort(nums, left, mid);->ret += mergeSort(nums, 0, 0);

  1. mergeSort(nums, 0, 0);

    left = right -> return 0;

  1. ret = 0;

    ret += mergeSort(nums, mid + 1, right);->ret += mergeSort(nums, 1, 1);

  1. mergeSort(nums, 1, 1);

    left = right -> return 0;

  1. mergeSort(nums, 0, 1);

    ret = 0;mid = 0;

    cur1=0;cur2=1;i=0

    进入while循环

    ret += mid - cur1 + 1;->ret += 0- 0+ 1=1
    tmp[i++] = nums[cur2++];->tmp[0] = nums[1];->tmp[0]=7

    i=1;cur2=2,跳出while循环

    cur1<mid,tmp[i++] = nums[cur1++];->tmp[1] = nums[0];->tmp[1]=9

    i=2;cur1=1

    进入for循环

    nums[0]=7

    nums[1]=9

    return 1

  2. mergeSort(nums, 0, 2);

    ret = 1;mid = 1;

    ret += mergeSort(nums, mid + 1, right);->ret += mergeSort(nums, 2, 2);

  3. mergeSort(nums, 2, 2);

    left = right -> return 0;

  4. mergeSort(nums, 0, 2);

    ret = 1;mid = 1;

    cur1=0;cur2=2;i=0

    进入while循环

    ret += mid - cur1 + 1;->ret = ret + 1- 0+ 1=3
    tmp[i++] = nums[cur2++];->tmp[0] = nums[2];->tmp[0]=5

    i=1;cur2=3,跳出while循环

    cur1<=mid,tmp[i++] = nums[cur1++];->tmp[1] = nums[0];->tmp[1]=7

    i=2;cur1=1

    cur1<=mid,tmp[i++] = nums[cur1++];->tmp[2] = nums[1];->tmp[2]=9

    i=3;cur1=2

    进入for循环

    nums[0]=5

    nums[1]=7

    nums[2]=9

    return 3

  5. mergeSort(nums, 0, 4);

    ret = 3;mid = 2;

    ret += mergeSort(nums, mid + 1, right); ->ret += mergeSort(nums, 3, 4);

  6. mergeSort(nums, 3, 4);

    ret = 3;mid = 3;

    ret += mergeSort(nums, left, mid);->ret += mergeSort(nums, 3, 3);

  7. mergeSort(nums, 3, 3);

    left = right -> return 0;

  8. mergeSort(nums, 3, 4);

    ret = 3;mid = 3;

    ret += mergeSort(nums, mid + 1, right);->ret += mergeSort(nums, 4, 4);

  9. mergeSort(nums, 4, 4);

    left = right -> return 0;

  10. mergeSort(nums, 3, 4);

    ret = 3;mid = 3;

    cur1=3;cur2=4;i=0

    进入while循环

    tmp[i++] = nums[cur1++];->tmp[0] = nums[3];->tmp[0] = 4

    i=1;cur1=4,跳出while循环

    cur2<=right;tmp[i++] = nums[cur2++];->tmp[1] = nums[4];->tmp[1] = 6

    i=2;cur2=5

    进入for循环

    nums[3]=4

    nums[4]=6

    return 3

  11. mergeSort(nums, 0, 4);

    ret = 3;mid = 2;

    cur1=0;cur2=3;i=0

    进入while循环

    ret += mid - cur1 + 1;->ret = ret + 2- 0+ 1= 3 +3 =6
    tmp[i++] = nums[cur2++];->tmp[0] = nums[3];->tmp[0]=4

    i=1;cur2=4

    nums[cur1]<=nums[cur2];->tmp[i++] = nums[cur1++];->tmp[1] = nums[0];->tmp[1]=5

    i=2;cur1=1

    ret += mid - cur1 + 1;->ret = ret + 2- 1+ 1= 6 +2 =8
    tmp[i++] = nums[cur2++];->tmp[2] = nums[4];->tmp[2]=6

    i=3;cur2=5

    跳出while循环

    cur1=1,cur2=5

    cur1<=mid,tmp[i++] = nums[cur1++];->tmp[3] = nums[1];->tmp[3]=7

    i=4;cur1=2

    cur1<=mid,tmp[i++] = nums[cur1++];->tmp[2] = nums[2];->tmp[4]=9

    i=5;cur1=3

    进入for循环

    nums[0]=4

    nums[1]=5

    nums[2]=6

    nums[3]=7

    nusm[4]=9

相关推荐
MiyamiKK575 分钟前
leetcode_字符串 409. 最长回文串
数据结构·算法·leetcode
半盏茶香26 分钟前
扬帆数据结构算法之雅舟航程,漫步C++幽谷——LeetCode刷题之移除链表元素、反转链表、找中间节点、合并有序链表、链表的回文结构
数据结构·c++·算法
哎呦,帅小伙哦33 分钟前
Effective C++ 规则41:了解隐式接口和编译期多态
c++·effective c++
CodeJourney.1 小时前
小型分布式发电项目优化设计方案
算法
DARLING Zero two♡1 小时前
【初阶数据结构】逆流的回环链桥:双链表
c语言·数据结构·c++·链表·双链表
9毫米的幻想1 小时前
【Linux系统】—— 编译器 gcc/g++ 的使用
linux·运维·服务器·c语言·c++
带多刺的玫瑰1 小时前
Leecode刷题C语言之从栈中取出K个硬币的最大面积和
数据结构·算法·图论
Cando学算法1 小时前
Codeforces Round 1000 (Div. 2)(前三题)
数据结构·c++·算法
薯条不要番茄酱1 小时前
【动态规划】落花人独立,微雨燕双飞 - 8. 01背包问题
算法·动态规划
小林熬夜学编程1 小时前
【Python】第三弹---编程基础进阶:掌握输入输出与运算符的全面指南
开发语言·python·算法