看到这道题你可能第一反应是下面这段代码:
public int reversePairs(int[] nums) {
int res=0;
for(int i=0;i<nums.length;i++){
for(int j=i+1;j<nums.length;j++){
if(i<j&&(double)nums[i]>2.0d*nums[j])
res++;
}
}
return res;
}
备注:nums[i]*2默认返回结果是一个int 类型的值,如果是很大的数超出了int 范围 ,那么就不能够得出正确的答案了。
提交一下,很快超出了时间限制。那这道题可以怎么做呢?最简单的是归并排序法。
归并排序法
首先让我们一起来看看归并排序算法是怎样实现的。
递归排序的核心思想是递归,先拆分再排序,我们来看代码:
import java.lang.reflect.Array;
import java.util.Arrays;
public class MergeSort {
//归并排序的递归
public static void mergeSort(int[] arr,int low,int high){
int mid=(low+high)/2;
if(low<high){
//处理左边
mergeSort(arr,low,mid);
//处理右边
mergeSort(arr,mid+1,high);
//归并
merge(arr,low,mid,high);
}
}
//先来写一个用于合并的方法
//从哪里开始,从哪里分割,从哪里结束,Mid是不能完全指向中间位置的
public static void merge(int[] arr,int low,int mid,int high){
//用于存储归并后的临时数组
int[] temp=new int[high-low+1];
//记录第一个数组中需要遍历的下标
int i=low;
//记录第二个数组中需要遍历的下标
int j=mid+1;
//用于记录在临时数组中存放的下标
int index=0;
//遍历两个数组取出小的元素放入临时数组中
while(i<=mid&&j<=high){
if(arr[i]<=arr[j]){
temp[index] = arr[i];
//让下标向后移动一位
i++;
}else{
temp[index]=arr[j];
j++;
}
index++;
}
//处理多余的数据
while(j<=high){
temp[index] = arr[j];
j++;
index++;
}
while(i<=mid){
temp[index] = arr[i];
i++;
index++;
}
//放回原来的数组
for(int k=0;k<temp.length;k++){
arr[k+low]=temp[k];
}
}
public static void main(String args[]){
int[] arr= new int[]{1,3,5,2,4,6,8,10};
//MergeSort mergeSort = new MergeSort();
// merge(arr,0,2,arr.length-1);
//System.out.println(Arrays.toString(arr));
mergeSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
}
了解了归并排序,现在让我们回归这道题。
做归并排序的时候,low——mid和mid+1——right都是排好序的,所以如果i在前一个序列里,j在后一个序列里,有nums[i]>2nums[j],就会有mid-i+1个满足大于2nums[j]的翻转对。
public static int mergeSort(int[] nums,int low,int high){
if(low>=high) return 0;
int mid =(high+low)/2;
int result = mergeSort(nums, low, mid) + mergeSort(nums, mid + 1,high);
int i=low,j=mid+1;
while(i<=mid){
double numi = (double) nums[i++] / 2.0d;
while (j <= high && numi <= (double) nums[j]) j++;
result += (high - j + 1);
}
merge(nums,low,mid,high);
return result;
}
public static void merge(int[] nums,int low,int mid,int high){
int i=low;
int j=mid+1;
int count=0;
int[] temp=new int[high-low+1];
int index=0;
int k=0;
while(i<=mid&&j<=high) {
//从大到小的排序
temp[k++] = (nums[i] >= nums[j]) ? nums[i++] : nums[j++];
}
while (i <= mid) temp[k++] = nums[i++];
while (j <= high) temp[k++] = nums[j++];
for(k=0;k<temp.length;k++){
nums[k+low]=temp[k];
}
}
public int reversePairs(int[] nums) {
if(nums.length==0||nums.length==1) return 0;
return mergeSort(nums,0,nums.length-1);
}