小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
剑指 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),因为归并排序需要用到一个临时数组。