翻转对 (LeetCode 493)

来源: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++;
    		}
    	}

    }
}

结果:超时

执行某巨长无比的测试用例时
翻转对 (LeetCode 493)_第1张图片
根据

https://blog.csdn.net/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);
   }
}

翻转对 (LeetCode 493)_第2张图片
快了好多
瞬间过了

记录一下改进的地方:
1.判断和处理溢出的方式
2.两段数组的比较方式

你可能感兴趣的:(算法刷题)