来源:LeetCode
知识点:排序、二分查找、分治、树状数组、线段树
思路:
官方题解
归并排序,每次算左边和右边比满足条件的翻转对
class Solution {
public int reversePairs(int[] nums) {
return mergeAndCount(nums,0,nums.length-1);
}
public int mergeAndCount(int[] nums,int start,int end) {
int cnt = 0;
if(start<end) {
int mid = (start+end)/2;
cnt += mergeAndCount(nums,start,mid);
cnt += mergeAndCount(nums,mid+1,end);
int j=mid+1;
int last = 0;
for(int i=start;i<=mid;i++) {
for(int k=j;k<=end;k++) {
// b溢出
if(nums[k]>1073741823 || nums[k]<-1073741823) {
double aa = nums[i]/2;
double bb = nums[k];
if(aa>bb) {
last++;
j++;
}
}else{
if(nums[i]>nums[k]*2) {
last++;
j++;
}
}
}
cnt += last;
}
merge(nums,start,mid,end);
}
return cnt;
}
public void merge(int[] nums,int start,int mid,int end) {
int[] templ = new int[mid-start+1];
int[] tempr = new int[end-mid];
for(int i=0;i<templ.length;i++) {
templ[i] = nums[start+i];
}
for(int i=0;i<tempr.length;i++) {
tempr[i] = nums[mid+i+1];
}
int pl = 0;
int pr = 0;
for(int i=start;i<=end;i++) {
if(pl==templ.length) {
nums[i] = tempr[pr];
pr++;
}else if(pr==tempr.length) {
nums[i] = templ[pl];
pl++;
}else if(templ[pl]<=tempr[pr]) {
nums[i] = templ[pl];
pl++;
}else {
nums[i] = tempr[pr];
pr++;
}
}
}
}
结果:超时
执行某巨长无比的测试用例时
根据
https://blog.youkuaiyun.com/haut_ykc/article/details/103446348
改进了比较翻转对的方式
int j=mid+1;
int last = 0;
for(int i=start;i<=mid;i++) {
for(int k=j;k<=end;k++) {
// b溢出
if(nums[k]>1073741823 || nums[k]<-1073741823) {
double aa = nums[i]/2;
double bb = nums[k];
if(aa>bb) {
last++;
j++;
}
}else{
if(nums[i]>nums[k]*2) {
last++;
j++;
}
}
}
cnt += last;
}
上面这段改成下面这段之后
int j=mid+1;
for(int i=start;i<=mid;i++) {
while(j<=end && nums[i]>(long)nums[j]*2)
j++;
cnt+=j-(mid+1);
}
}
快了好多
瞬间过了
记录一下改进的地方:
1.判断和处理溢出的方式
2.两段数组的比较方式