剑指offer51:数组中的逆序对

这东西居然可以和归并连起来,真是不可思议,受教了

1.暴力

我们当然可以对每一个数字,求出在其之后的比其更小的数字,然后计数,这样时间复杂度是O(n^2),你去试吧,会爆掉的

2.归并

你有想过归并么,我看到归并,立刻想可不可以先排序然后直接用高斯求和算一下,发现焯~,不能这样改变顺序啊,那归并是个什么情况?emmm看完题解......牛逼!

力扣

这里要不还是举个栗子好了:[7,5,6,4]

大家脑子里要是有递归的想象的话,它是这样的,就好比先把7564拆成了4个数,然后一个一个并起来,例如对7,5并起来[7,5]是一个逆序对,6,4并起来,他们也有了一个逆序对了。然后我们对[7,5]和[6,4]分析,试想一下,如果我们对两个无序数组来计算他们之间有多少个逆序对,是不是很麻烦?而我们用归并的话,自底向上实现一个排序,就会方便很多。例如之前的两个我们如果排成[5,7],[4,6]。

那么又有一个问题,区间我们怎么知道呢?所以我们的函数里需要记录数组的左右区间,这样,我们可以用两个下标or指针标记到5和4,只要左边数组的下标所指的nums[left]>nums[right],我们是不是就知道他们之间的逆序对可以加上mid-left+1个呢?

别忘了还要在计算的过程中归并,以便比他更高一级的递归层可以直接用到。我们需要开一个新的数组来存储排序的数组部分,对应的区间是[l,r]。那存储下来是干嘛的呢,当然是用来在在函数最后更新nums数组的拉,不然你排在临时数组里面只是排个寂寞~

具体代码在这里了:

class Solution {
public:
    int reversePairs(vector<int>& nums) {
        vector<int> tmp(nums.size());
        return mergeSort(nums,tmp,0,nums.size()-1);
    }
    int mergeSort(vector<int>&nums,vector<int>&tmp,int l,int r)
    {
        if(l>=r) return 0;
        int mid=(l+r)/2;
        int num=mergeSort(nums,tmp,l,mid)+mergeSort(nums,tmp,mid+1,r);
        int left=l,right=mid+1,pos=l;
        //这里有两种递增num的方法
        //1.对右边的数组中的每一个数,判断左边数组有多少个数字可以和他组成逆序对
        //2.对左边的数组中的每一个数,计算右边有多少个数字可以组成逆序对
        //这里实现第一种更方便一点点 采取的是第一种方法
        while(left<=mid&&right<=r)
        {
            if(nums[left]<=nums[right])
            {
                tmp[pos]=nums[left++];
                //num+=right-mid-1;第二种
            }
            else
            {
                num+=mid-left+1;
                tmp[pos]=nums[right++];
            }
            ++pos;
        }
        while(left<=mid)
        {
            tmp[pos++]=nums[left++];
            //num+=right-mid-1;第二种
        }
        while(right<=r)
        {
            tmp[pos++]=nums[right++];
        }
        // for(int i=l;i<=r;++i)
        // {
        //     nums[i]=tmp[i];
        // }
        copy(tmp.begin() + l, tmp.begin() + r + 1, nums.begin() + l);
        return num;
    }
};

不过这里采用不同的思路会有一些细微的差别,有的地方调用标准库也会有相应的时间上的提升。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值