[题记]数组中的逆序对——LeetCode

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例 1:
输入: [7,5,6,4]
输出: 5
 

限制:
0 <= 数组长度 <= 50000

一:直接 暴力,当然超时了~~

class Solution {
public:
    int reversePairs(vector<int>& nums) {
        int ans = 0;
        int len = nums.size();
        for( int i = 0; i < len - 1; i++ ) {
            for( int j = i + 1; j < len; j++ ) {
                if( nums[i] > nums[j] ) ans++;
            }
        }
        return ans;
    }
};

二:(分治思想)归并排序
为什么要用归并排序?
归并排序是将一个数组不断的分成两部分,直到每一部分为1个数字,然后进行大小关系的调整,再进行合并,直到最后合并的长度等于原数组,排序完成。
递归算法超时的原因是前一次的遍历无法为下一次的遍历提供有用的信息,这个信息就是数字的大小关系,如果知道了数字的大小关系,我们就可以节省了大量的遍历时间,从而提高时间效率。
而归并排序在合并阶段,每一部分都是有顺序的,这样就为我们寻找逆序对提供了数与数的大小关系。

class Solution {
public:
    int tmp[50005];
    int ans;
    void merger( int begin, int end, vector<int>& nums) {
        if( begin == end ) return ;
		
        int mid = begin + (end - begin) / 2;//防止溢出
        
        //将数组分为左右两部分
        merger(begin, mid, nums);
        merger(mid + 1, end, nums);

        int left = begin;
        int right = mid + 1;
        int k = begin;
		
		//比较两个部分的数字
        while( left <= mid&& right <= end ) {
            if( nums[left] <= nums[right] ) {
                tmp[k++] = nums[left++];
            }
            else {
            	/*由于左边部分都是从小到大有序的,当右边的数字小与左边的数字时
            	表明从left索引到mid索引的数字都是大于右边right索引的数字的
            	也就形成了min - left + 1个逆序对,从而缩短了时间。*/
                tmp[k++] = nums[right++];
                ans+= mid - left + 1;
            }
        }
		
		//将剩下的数字加入tmp临时数组
        while( left <= mid ) {
            tmp[k++] = nums[left++];
        }
        while( right <= end ) {
            tmp[k++] = nums[right++];
        }
		
		//将合并后的两部分返回原数组
        for( int i = begin; i <= end; i++ ) {
            nums[i] = tmp[i];
        }

    }

    int reversePairs(vector<int>& nums) {
        int len = nums.size();
        if( len == 0 ) return 0;
        
        ans = 0;
        merger(0, len - 1, nums);//范围:闭区间[0, len - 1]
        
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值