Reverse Pairs

Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j].

You need to return the number of important reverse pairs in the given array.

Example1:

Input: [1,3,2,3,1]
Output: 2
Example2:

Input: [2,4,3,5,1]
Output: 3
Note:
The length of the given array will not exceed 50,000.
All the numbers in the input array are in the range of 32-bit integer.

在学习王争的数据结构与算法之美看到老师讲分治法,首先是分治法应用于归并排序,然后解决这道题。分治法是一种解决问题的思想,分解问题,解决子问题,合并答案。
这道题实说要找出数组中有多少个逆序对,暴力法复杂度 O ( n 2 ) O(n^{2}) O(n2),这道题可以巧妙地用归并排序解决。

为了求的整个数组的逆序数,我们可以分别求各一半数组的逆序对数,假设分别为a个和b个,再求两个子数组之间的逆序数,假设为c,最终的逆序数即为a+b+c.

我们在合并函数中可以同时计算出两个子数组间的逆序数,该结果就作为上一层子数组的逆序数,自下而上递归回去就能算出整个数组的逆序数了。

注:这儿我们需要用long long来存数组的值,因为有个2*nums[i]操作,若用int会造成数值溢出。总的来说就是在归并排序代码基础上加了个求逆序数的操作。

class Solution {
public:
    int reversePairs(vector<int>& nums) {
        int res=0;
        vector<long long> nums_long(nums.begin(),nums.end());
        mergeSortHelper(nums_long,0,nums.size()-1,res);
        //for (int a:nums) cout<<a<<" ";
        
        return res;
    }
    void mergeSortHelper(vector<long long>& nums,int low,int high,int& numbers)
    {
        if (low>=high) return;
        int mid=(low+high)/2;
        mergeSortHelper(nums,low,mid,numbers);
        mergeSortHelper(nums,mid+1,high,numbers);
        merge(nums,low,mid,high,numbers);
    }
    void merge(vector<long long>& nums,int low,int mid,int high,int& numbers)
    {
        int i=low,j=mid+1,k=0;
        vector<long long> tmp(high-low+1);
        // 子数组内的数据已经是有序的了,故找到nums[i]>2*nums[j],那么i后面的所有数据都大于2*nums[j]
        while(i<=mid&&j<=high)
        {
            if(nums[i]<=2*nums[j]) i++;
            else
            {
                numbers += mid-i+1;
                j++;
            }
        }
        // 这段代码是将两个有序子数组合并成一个有序的数组
        i=low,j=mid+1;
        while(i<=mid&&j<=high)
        {
            //cout<<nums[i]<<" "<<nums[j]<<endl;
            if(nums[i]<nums[j]) tmp[k++]=nums[i++];
            else
            {
                tmp[k++]=nums[j++];
            }
        }
        if(i>mid)
        {
            while(j<=high) tmp[k++]=nums[j++];
            
        }
        else
        {
            while(i<=mid) tmp[k++]=nums[i++];
        }
        
        for (i=0;i<high-low+1;i++)
        {
            nums[low+i]=tmp[i];
        }
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值