day39:数组中的逆序对(归并排序模板)

问题描述:
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:

  • 输入: [7,5,6,4]
  • 输出: 5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof

注意该问题是逆序数对个数之和,如果是从小到大的数列,那么逆序数对总数为0,如果逆序数对是从大到小排列,那么逆序数对总数会是很高计算。例如【5,4,3,2,1】逆序数对总和为4+ 3 +2 + 1 =10。
问题求解使用到了归并排序,在排序整个数组的过程中将逆序的数对个数进行求解,使用递归进行归并排序,将整个数组分成两部分,分别用 i , j 指向这两个数组的起始位置,比较 nums[i]和nums[j]的大小 ,需要将小的那一个放入temp数组,如果nums[i]>nums[j],此时就意味着出现了逆序数对,注意理解的时候mid-i+1这个计算结果是在有序数组的基础上计算的,只有有序,数组中的元素才会放入到temp中,由于该过程涉及到递归,所以理解的时候要自下至上理解。如果数组有剩余部分没有遍历到,那么剩余的数组要拷贝到原始数组中。
结合该链接理解为什么是mid-i+1

归并排序模板

void merge(vector<int> nums,int l,int r)
{
        if(l>=r)return;
        int mid=l+r>>1;
        merge(nums,l,mid);  merge(nums,mid+1,r);
        vector<int> tem;
        int i=l,j=mid+1;
        while(i<=mid&&j<=r)
        {
            if(nums[i]<=nums[j]) tem.push_back(nums[i++]);
            else  tem.push_back(nums[j++]);
        }
        while(i<=mid)tem.push_back(nums[i++]);
        while(j<=r)tem.push_back(nums[j++]);
        i=l;
        for(auto t:tem) nums[i++]=t;//把tem排好序的数组放到原始数组里
        
}
算法时间复杂度空间复杂度解释
自底向上数组实现O(nlogn)O(n)不需要递归,需要额外的空间帮助合并
自底向上list实现O(nlogn)O(1)不需要递归
自顶向上数组实现O(nlogn)O(n+logn)用到了数组,此外递归需要栈空间为logn
自底向上list实现O(nlogn)O(logn)递归需要栈空间为logn

自底向上链表实现可以参考LeetCode 148 排序链表

class Solution {
public:
    int merge(vector<int>&nums,int l,int r)
    {
        if(l>=r) return 0;
        int mid=l+r >> 1;
        int res=merge(nums,l,mid)+merge(nums,mid+1,r);
        int i=l,j=mid+1;
        vector<int> temp;
        while(i<=mid&&j<=r)
        {
            if(nums[i]<=nums[j]) temp.push_back(nums[i++]);
            else
            {
                temp.push_back(nums[j++]);
                res+=mid-i+1;
            }
        }
        while(i<=mid) temp.push_back(nums[i++]);
        while(j<=r) temp.push_back(nums[j++]);
        i=l;
        for(auto x:temp) nums[i++]=x;
        return res;
    }
    int inversePairs(vector<int>& nums) {
        return merge(nums,0,nums.size()-1);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值