力扣刷题-51.数组中的逆序对、归并排序、分治思想

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
 示例 1:
  输入: [7,5,6,4]
  输出: 5

  1. 分治思想
      分治就是分而之,面对一个规模复杂的问题,把它分解成一系列的简单子问题,对子问题求解的结果进行合并从而实现对整个问题的求解。
      通过不断的递归,每次尽可能的缩小问题的规模,直至满足基线条件;基线条件必须尽可能的简单,最好能直接得到需要结果。比如对一个数组排序,基线条件就是当数组只有一个元素的时候,就认为是有序的,直接返回结果。
      快速排序、归并排序都是采用的分治以及递归的思想。

  2. 归并排序
      将两个有序的数组合并成一个有序数组称为归并。归并排序包含了两个过程:
      ①:从上往下的分解:把当前区间一分为二,直至分解为若干个长度为1的子数组
      ②:从下往上的合并:两个有序的子区域两两向上合并
      如下图所示:
    在这里插入图片描述
      归并排序的一般步骤:
      ①.分解:把当前区间一分为二,分解点即中间点mid = (left+right)/2
      ②.求解:分别递归左右两个子区间[left…mid] 和 [mid+1…right]进行归并排序。递归的终结条件是子区间长度为1。
      ③.合并:把两个有序子数组合并需要占用一个临时空间,依次挪动两个子区间的指针,比较元素值大小,将较小的值存入临时空间的开头。将两个有序区间归并成一个临时有序区间[left…right],并将结果拷贝到原数组的区间[left…right],使原始数组[left…right]变为有序。

  3. 题目分析
      本题是典型的归并排序例子。若左边元素值大于右边元素值则存在逆序对,逆序对是归并排序的附加结果。
      左右两个子区间都是有序的,若左边区间中元素nums[i]>nums[j]则存在逆序对,因此左边区间中子区间[i,mid]的所有元素都和nums[j]构成了逆序对,减少了不必须要的重复计算。

  4. 代码示例

class Solution {
public:
    int resault = 0;//全局变量,用于保存结果
    int reversePairs(vector<int>& nums) {
        vector<int> temp = vector(nums.size(),0);//创建临时数组,减少每次创建的开销
        mergeSort(nums,temp,0,nums.size()-1);//归并排序
        return resault;
    }
    void mergeSort(vector<int>& nums,vector<int>& temp,int left ,int right)
    {
        if( left >= right) return;//满足基线条件,直接返回
        int mid = left+(right-left)/2;//分隔点
        mergeSort(nums,temp,left,mid);//对左区间进行归并排序
        mergeSort(nums,temp,mid+1,right);//对右区间进行归并排序
        int i = left;//左区间指针
        int j = mid+1;//右区间指针
        int t = 0;//临时数组指针
        while( i <= mid && j <= right)
        {
            if( nums[i] > nums[j] )//若左区间中元素值大于右区间中元素值,则存在逆序对
            {
                temp[t++] = nums[j++];
                resault += (mid - i + 1);//仅在并归排序中增加一行代码,全局变量保存逆序对数量
            }
            else
            {
                temp[t++] = nums[i++];
            }
        }
        while(i<= mid)//将左边剩余元素填充进temp中
        {
            temp[t++] = nums[i++];
        }
        while(j <= right)//将右序列剩余元素填充进temp中
        {
            temp[t++] = nums[j++];
        }
        t= 0;
         //将temp中的元素全部拷贝到原数组[left,right]中
        while(left <= right)
        {
            nums[left++] = temp[t++];
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值