剑指 Offer 51. 数组中的逆序对

165 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动

剑指 Offer 51. 数组中的逆序对

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

示例 1:

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

限制:

0 <= 数组长度 <= 50000

解题思路

在归并排序的合并阶段中,本质上是 合并两个排序数组 的过程,而每当遇到 左子数组当前元素 > 右子数组当前元素 时,意味着 「左子数组当前元素 至 末尾元素」 与 「右子数组当前元素」 构成了若干 「逆序对」。

因此在归并排序的过程中,可以穿插逆序对的计算,归并两个排序数组时当出现右区间元素,大于左区间元素的时候,说明左区间内的元素和当前元素都能组成逆序对

代码

class Solution {
    int cnt=0;
    public int reversePairs(int[] nums) {

        mergeSort(nums,0,nums.length-1);
        return cnt;
    }
    public void mergeSort(int[] nums,int l,int r)
    {
        int mid=(r-l)/2+l;
        if(l<r)
        {
            mergeSort(nums,l,mid);
            mergeSort(nums,mid+1,r);
            merge(nums,l,r);
        }
        
        
    }
        public void merge(int[] nums,int l,int r)
        {
            int[] t=new int[r-l+1];int mid=(r-l)/2+l;
            int i=l,j=mid+1,idx=0;
            while(i<=mid&&j<=r){
                if(nums[i]<=nums[j])
                  t[idx++]=nums[i++];
                else{
                    cnt+=mid-i+1;
                    t[idx++]=nums[j++];
                }  
            }
            while(i<=mid)
                 t[idx++]=nums[i++];
            while(j<=r)
                 t[idx++]=nums[j++];
             for(int k=0;k<r-l+1;k++)
                 nums[l+k]=t[k];
        }
}

记序列长度为 n。

  • 时间复杂度:同归并排序 O(nlogn)。
  • 空间复杂度:同归并排序 O(n),因为归并排序需要用到一个临时数组。