难度困难
在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4] 输出: 5
暴力双循环,最容易想到的思路,超时
class Solution {
public int reversePairs(int[] nums) {
int cnt=0;
int n = nums.length;
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(nums[i] > nums[j])
cnt++;
}
}
return cnt;
}
}
这道题很巧妙地利用了归并排序,即子数组有序的思想,视频讲解更清晰:视频讲解链接
归并排序模板:
class Solution {//归并排序模板
int[] aux;
public int reversePairs(int[] nums) {
int n = nums.length;
aux = new int[n];
sort(nums,0,n-1);
return cnt;
}
public void sort(int[] nums,int l,int r){
if(l>=r) return;
int mid = (l+r)/2;
sort(nums,l,mid);
sort(nums,mid+1,r);
merge(nums,l,mid,r);
}
public void merge(int[] nums,int l,int mid,int r){
int i=l,j=mid+1;
for(int k=l;k<=r;k++){
aux[k] = nums[k];
}
int index=l;
while(i<=mid || j<=r){
if(i>mid) nums[index++] = aux[j++];
else if(j>r) nums[index++] = aux[i++];
else if(aux[i] <= aux[j]) nums[index++] = aux[i++];
else{
nums[index++] = aux[j++];
}
}
}
}
只需要再次基础上添加一行代码即可:
class Solution {//巧妙的使用归并排序
int cnt=0;
int[] aux;
public int reversePairs(int[] nums) {
int n = nums.length;
aux = new int[n];
sort(nums,0,n-1);
return cnt;
}
public void sort(int[] nums,int l,int r){
if(l>=r) return;
int mid = (l+r)/2;
sort(nums,l,mid);
sort(nums,mid+1,r);
merge(nums,l,mid,r);
}
public void merge(int[] nums,int l,int mid,int r){
int i=l,j=mid+1;
for(int k=l;k<=r;k++){
aux[k] = nums[k];
}
int index=l;
while(i<=mid || j<=r){
if(i>mid) nums[index++] = aux[j++];
else if(j>r) nums[index++] = aux[i++];
else if(aux[i] <= aux[j]) nums[index++] = aux[i++];
else{
nums[index++] = aux[j++];
cnt = cnt+(mid-i+1);//添加一行计数
}
}
}
}