leetcode-005-51. 数组中的逆序对


第五天刷题,嗯,深呼吸,要坚持呀!


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

 

示例 1:

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

 

限制:

0 <= 数组长度 <= 50000


来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题目描述很简单,但是我想了很久都没有思路,尝试着暴力解决,很不幸,超时了,估算一下暴力的复杂度 n ∗ ( n + 1 ) / 2 n*(n+1)/2 n(n+1)/2。实在没有思路,所以我看了一下评论,提到了归并排序,ok,我立马明白了。但我觉得我本身对归并算法的本质仍然理解的不够深入。否则我不会失败于思路上。
归并算法:

//升序排序
sort(left, right)
{
	center = (left+right)/2
	nums[left:center] = sort(left, center)
	nums[center+1, right] = sort(center+1, right)
	nums[left:center] = merge(nums[left:center], nums[center+1:right])
}
merge(nums1, nums2) //有序数列的归并
{
	i, pos1, pos2=0
	while(pos<nums1.size && pos<nums2.size)
	{
		if(nums1[po1]>nums2[pos2])
			tmp[i++] = nums2[pos2++]
		else
			tmp[i++] = nums1[pos1++]
	}
	while(pos<nums1)
	{}
	while(pos<nums2)
	{}
}

很棒,这是有一个归并算法的伪代码,它的复杂度是 n ∗ l o g 2 ( n ) n*log_{2}(n) nlog2(n)
在这里插入图片描述*图片来源:https://www.cnblogs.com/chengxiao/p/6194356.html
*
归并排序的复杂度:sort函数被调用了 l o g 2 n log_{2}n log2n次,sort函数中的merge函数的复杂度为 n n n,所有复杂度为 n ∗ l o g 2 n n*log_{2}n nlog2n

逆序是在归并排序中统计的,当归并的时候,左边的数字大于右边,就是一个逆序。代码如下:

class Solution {
public:
    int count;
public:
    void sort(vector<int>& nums, int left, int right) //分治 排序
    {
        if(left+1==right)	//只有两个元素
        {
            if(nums[left]>nums[right])
            {
                this->count++;
                int tmp = nums[left];
                nums[left] = nums[right];
                nums[right] = tmp;
            }
            return;
        } //只有一个元素
        else if(left==right)
            return;
        int center = (left+right)/2;
        sort(nums, left, center); //左子串
        sort(nums, center+1, right); //右子串
        merge(nums, left, center, right); //归并
    }

    void merge(vector<int>& nums, int left, int center, int right)
    {
        int i=0;
        int tmp[right-left+1];
        int l_pos = left, r_pos = center+1;
        while(l_pos<=center && r_pos<=right)
        {
            if(nums[l_pos]>nums[r_pos]) //左边比右边大
            {
                this->count += center-l_pos+1;  //当前左子串的这个元素的左侧元素们都比右子串当前元素大
                tmp[i++] = nums[r_pos];
                r_pos++;
            }
            else
            {
                tmp[i++] = nums[l_pos];
                l_pos++;
            }
        }
        while(l_pos<=center)
        {
            tmp[i++] = nums[l_pos];
            l_pos++;
        }
        while(r_pos<=right)
        {
            tmp[i++] = nums[r_pos];
            r_pos++;   
        }

        for(int k=left,j=0; k<=right; k++,j++)
            nums[k] = tmp[j];
    }

    int reversePairs(vector<int>& nums) {
        if(nums.size()==0)
            return 0;
        this->count = 0;    
        sort(nums, 0, nums.size()-1);
        return this->count;
        
    }
};

//暴力解决
// int count = 0;
// int size = nums.size();
// for(int i=0; i<size; i++)
// {
//     int j=i+1;
//     while(j<size)
//     {
//         if(nums[i]>nums[j])
//         {
//             count++;
//         }
//         j++;

//     }
// }

// return count;

虽然可能讲的不是很透彻,因为归并排序我也只是会写,我觉得我没有摸到核心,但积少成多!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值