题意:
Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j].
这种不能破坏 i 和j “相对关系” 的情况去统计一些结果的题,都可以考虑merge sort.
merge sort解法:
比如merge sort 中分解成2块 [5 8 7 6] | [2 1 3 4], 那么统计左边和右边符合条件的,
5: 2 1 --->2个
8: 2 1 3 --->3个
7 : 2 1 3 -->3个
6: 2 1 --> 2个
总共10个
Key point: merge sort 时 在merge 之前 左边 index 一定小于 右边index
当然真正merge sort 是 自底向上的, 所以在merge 之前左右都是排序好的。
整个过程:
1.先分解成: [5 8] [7 6] [2 1 ] [ 3 4 ]
2. 统计这里的count,
3. 然后merge 变成 [5 8 ] [6 7 ] and [1 2 ] [3 4 ]
4. 继续统计 count ([5 8 ] [6 7 ] ) and count([1 2 ] [3 4 ])
5. 再merge [5 6 7 8] and [1 2 3 4]
6. count([5 6 7 8] [1 2 3 4])
7. 最后Merge 成[1 2 3 4 5 6 7 8]
注意1. 每次在count 前 左右两边的数组已经排序好了
2. merge 之前左边数组 任意 left_index < right _index 只有merge 完后才会破坏这种index 关系, 所以要在merge 之前去count
//1 用BST 会 TLE
//2. 用 merge sort
public class Solution {
public int reversePairs(int[] nums) {
return merge_count(nums,0, nums.length-1);
}
private int merge_count(int[] nums, int start, int end){
if(start<end){
int mid = start + (end-start)/2;
int count = merge_count(nums,start, mid) + merge_count(nums,mid+1,end); // sub 数组的
//再统计当前准备merge的,注意此时左右已经排好序了,经过上面的merge,例如 left = [5 6 7 8] right =[1 2 3 4]
int j = mid+1;
for(int i=start; i<=mid; i++){
while(j<=end && nums[i] > (long)nums[j] *2)
j++;
count += j- (mid+1);
}
merge(nums,start,mid,end);
return count;
}
return 0;
}
// merge left = [1 2 5 8] right =[3 4 6 9]
private void merge(int[] nums, int start, int mid, int end){
int[] tmp = new int[end-start+1]; //merge sort 需要的额外空间在此
int i= start;
int j= mid+1;
int k=0;
//for(; i<mid && j<end; tmp[k++]=(arr[i]<arr[j]?arr[i++]:arr[j++]));
while(i<=mid && j<=end){
if(nums[i] < nums[j]){
tmp[k++] = nums[i];
i++;
}
else{
tmp[k++] = nums[j];
j++;
}
}
//处理merge 完剩余部分
while(i<=mid){tmp[k++] = nums[i++];}
while(j<=end) {tmp[k++] = nums[j++];}
// 把tmp copy 进nums
int s = start;
for(int num: tmp){
nums[s++] = num;
}
}
}
浙公网安备 33010602011771号