题意:
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; } } }