-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy path493. Reverse Pairs.java
executable file
·90 lines (70 loc) · 4.11 KB
/
493. Reverse Pairs.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
M
tags: Divide and Conquer, Merge Sort, BST, Segment Tree, Binary Indexed Tree
给一串数字, count total reverse pair `nums[i] > 2*nums[j]`, i < j
This problem can be solved with Merge sort concept, BST, Segment Tree and Binary Indexed Tree. Good for learning/review.
#### Merge Sort, Divide and Conquer
- Using merge sort concept (NOT merge sort impl).
- One very simply desire: if we want to know # elements between [i, j] such that `nums[i] > 2*nums[j]`, it would be so great if array is **sorted**!
- If sorted, fix index i, keep j++ for all `nums[i]/2.0 > nums[j]`
- We CANNOT just sort entire array. WHY? Because it distrupts the value of curr index i, and the restriction is: `find matching elements on right side of curr index i`
- BUT, what about just sort `right side of i`, and make sure the subproblem (i+1, end) is solved first?
- 灵感: use merge sort concept.divide and conquer [i ~ n] into 2 sections:
- 1) solve subProblem(start,mid) & subProblem(mid+1, end). sort the sub array so that it can be used recursively at parent level.
- 2) solve the curr pblem: for all [i, mid], check against [mid+1, end].
- Question1: does it cover all use cases?
- First, subProblem(start,mid) & subProblem(mid+1, end) recursively solves its own range
- Last, the only range is the current level problem check `[i, mid]` against its entire right side range: `[mid+1, end]`. DONE. all covered.
- Question2: what it is okay for `subProblem(start,mid) & subProblem(mid+1, end)` partially sort the array?
- that is the goal: 1) we want the right side range to be sorted; 2) left range is sorted but it does not matter since we treat [start, mid] as 1 group
- use classic while loop `while(j<=e && nums[i]/2.0 > nums[j])` to count pairs
#### Segment tree
- TODO
- split the array into index-based segment tree, where each element is at leaf
- store min of range: use min to determine if certain range is needed for further query
- query for each element right side range (i + 1, end), where it recursively query&aggregate sub-range if meeting requirement `nums[i] > 2*nums[j]`
- only when target > subRange.min * 2: there are possible candidates, query further
- worst case O(n^2) when all tailing elements are meeting requirement.
#### BST
- TODO
- Build the BST based on node value. It will be not applicable if we search after entire tree is built (our goal is right range), so we need to build right elements, and search/count right after the elements is added
- Worst case is still O(n^2), if all added nodes are meeting requirement
- search(tree, curr / 2.0)
#### O(n^2)
- check each one of them
```
/*
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.
*/
class Solution {
public int reversePairs(int[] nums) {
if (nums == null || nums.length == 0) return 0;
return mergeSort(nums, 0, nums.length - 1);
}
private int mergeSort(int[] nums, int start, int end) {
// check end point
if (start >= end) return 0;
// for each index i in nums, need to cover [i+1, ... n-1] to satisfy `reverse pair` rule
// divide and conquer [i ~ n] into 2 sections:
// 1) solve subProblem(start,mid) & subProblem(mid+1, end), 2) cover the rest range: for all [i, mid], check against [mid+1, end].
int mid = start + (end - start) / 2;
int count = mergeSort(nums, start, mid) + mergeSort(nums, mid + 1, end);
// count pair
for (int i = start, j = mid + 1; i <= mid; i++) {
while (j <= end && nums[i] / 2.0 > nums[j]) j++; // `num/2.0` to avaoid overflow
count += j - (mid + 1); // use index i (ahead of mid point) to compare all elements after mid point
}
Arrays.sort(nums, start, end + 1); // partial sort of range [start, end] inclusively
return count;
}
}
```