给定一个数组 nums ,如果 i < j 且 nums[i] > 2*nums[j] 我们就将 (i, j) 称作一个重要翻转对。
你需要返回给定数组中的重要翻转对的数量。
示例 1:
输入: [1,3,2,3,1]
输出: 2
示例 2:
输入: [2,4,3,5,1]
输出: 3
题解(一):归并排序,在归并排序的过程中,假设对于某归并数组而言,我们已经分别求出了其左右子数组的翻转对数目,并已将左右子数组分别排好序,则该数组中的翻转对数目,就等于两个子数组的翻转对数目之和,加上翻转对左右端点分别位于左右两个子数组的翻转对数目。
class Solution {
public int reversePairs(int[] nums) {
if(nums.length==0)
return 0;
return mergeSort(nums,0, nums.length-1);
}
//归并排序算法
public int mergeSort(int[]nums,int left,int right){
if(left==right)
return 0;
int mid=(left+right)/2;
//递归
int ans=mergeSort(nums,left,mid)+mergeSort(nums,mid+1,right);
int left_bound=left;
int right_bound=mid+1;
//找出翻转对的数量(左右端点分别位于左右两个有序数组中)
while(left_bound<=mid){
while(right_bound<=right&&(long)(nums[left_bound])>2*(long)nums[right_bound]){
right_bound++;
}
ans+=(right_bound-mid-1);
left_bound++;
}
int[]sorted=new int[right-left+1];
int leftPtr=left;
int rightPtr=mid+1;
int i=0;
//左右两个有序数组合并
while(leftPtr<=mid||rightPtr<=right){
if(leftPtr>mid){
sorted[i++]=nums[rightPtr++];
}else if(rightPtr>right){
sorted[i++]=nums[leftPtr++];
}else{
if(nums[leftPtr]<nums[rightPtr]){
sorted[i++]=nums[leftPtr++];
}else{
sorted[i++]=nums[rightPtr++];
}
}
}
for (int j = 0; j < sorted.length; j++) {
nums[left + j] = sorted[j];
}
return ans;
}
}
题解(二):构造树状数组
class Solution {
public int reversePairs(int[] nums) {
Set<Long> allNumbers = new TreeSet<Long>();
for (int x : nums) {
allNumbers.add((long) x);
allNumbers.add((long) x * 2);
}
// 利用哈希映射将离散整数投影到连续空间
Map<Long, Integer> values = new HashMap<Long, Integer>();
int idx = 0;
for (long x : allNumbers) {
values.put(x, idx);
idx++;
}
int ret = 0;
Tree bit = new Tree(values.size());
for (int i = 0; i < nums.length; i++) {
int left = values.get((long) nums[i] * 2), right = values.size() - 1;
ret += bit.query(right + 1) - bit.query(left + 1);
bit.update(values.get((long) nums[i]) + 1, 1);
}
return ret;
}
}
//树状数组类
class Tree {
int[] tree;
int n;
public Tree(int n) {
this.n = n;
this.tree = new int[n + 1];
}
public static int lowbit(int x) {
return x & (-x);
}
public void update(int x, int d) {
while (x <= n) {
tree[x] += d;
x += lowbit(x);
}
}
public int query(int x) {
int ans = 0;
while (x != 0) {
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
}