forked from gouthampradhan/leetcode
-
Notifications
You must be signed in to change notification settings - Fork 0
/
ReversePairs.java
121 lines (104 loc) · 3.35 KB
/
ReversePairs.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
package divide_and_conquer;
import java.util.*;
/**
* Created by gouthamvidyapradhan on 30/06/2018.
* Given an array nums, we call (i, j) an important reverse pair if i < j and nums[i] > 2*nums[j].
You need to return the number of important reverse pairs in the given array.
Example1:
Input: [1,3,2,3,1]
Output: 2
Example2:
Input: [2,4,3,5,1]
Output: 3
Note:
The length of the given array will not exceed 50,000.
All the numbers in the input array are in the range of 32-bit integer.
Solution: O(n log n):
Example: 1,3,2,3,1
1. Sort the array in non-increasing order (if there is a collision, sort by lower index).
So the sorted array will be (3, 3, 2, 1, 1) having indexes (1, 3, 2, 0, 4)
2. Maintain a prefix sum of index (starting from 1) for the sorted array. So, prefix sum for the above sorted array is
(1, 2, 3, 4, 5)
Now, the basic idea is to iterate from index n - 1 to 0 in the original array and for each element calculate the
element p (num[i] x 2) and find the upper bound of the element p in sorted array which is 3 at index 1 in this case
and add prefix sum of the index 1 to the result. So the result now becomes 2.
To maintain a prefix sum and update it efficiently we have to use a BIT or Fenwick tree.
*/
public class ReversePairs {
class Pair{
int i, n;
Pair(int i, int n){
this.i = i;
this.n = n;
}
int getN(){
return n;
}
int getI(){
return i;
}
}
/**
* Main method
* @param args
* @throws Exception
*/
public static void main(String[] args) throws Exception{
int[] A = {2,4,3,5,1};
System.out.println(new ReversePairs().reversePairs(A));
}
public int reversePairs(int[] nums) {
List<Pair> list = new ArrayList<>();
Ftree ft = new Ftree(nums.length);
for(int i = 0; i < nums.length; i ++){
list.add(new Pair(i, nums[i]));
ft.update(i, 1);
}
Collections.sort(list, (Comparator.comparing(Pair::getN).reversed().thenComparing(Pair::getI)));
int[] indexMap = new int[nums.length];
for(int i = 0, l = list.size(); i < l; i ++){
indexMap[list.get(i).getI()] = i;
}
int ans = 0;
for(int i = nums.length - 1; i >= 0; i --){
ft.update(indexMap[i], -1);
int index = binarySearch(list, (long)nums[i] * 2);
if(index > -1){
ans += ft.getRangeSum(index);
}
}
return ans;
}
private int binarySearch(List<Pair> list, long n){
int l = 0, h = list.size() - 1;
int ans = -1;
while(l <= h){
int m = l + (h - l) / 2;
if(list.get(m).n > n){
ans = m;
l = m + 1;
} else{
h = m - 1;
}
}
return ans;
}
private class Ftree {
private int[] a;
Ftree(int n) {
a = new int[n + 1];
}
void update(int p, int v) {
for (int i = p + 1; i < a.length; i += (i & (-i))) {
a[i] += v;
}
}
int getRangeSum(int p) {
int sum = 0;
for (int i = p + 1; i > 0; i -= (i & (-i))) {
sum += a[i];
}
return sum;
}
}
}