垃圾如我,先mark一下吧,听说树状数组可以更简便,然而一直还没看之先mark一下吧
既然不用树状数组,那就只能用merge&sort和bst了,大神说了bst会超时,只能用avl,然后我试了试bst还真的会超时:
class Solution {
public:
int sum = 0;
struct node{
node* r, *l;
int num, count;
node() :r(NULL), l(NULL), num(0), count(0){};
node(int num, int count) :r(NULL), l(NULL), num(num), count(count){};
};
void Add(node* &u, int n, int count){
if(u == NULL){
u = new node(n, count);
}
else{
if(n >= u->num){
Add(u->r, n, 0);
}else{
u->count++;
Add(u->l, n, 0);
}
}
}
void countNum(node* &u, int n, int & ans){
if(u == NULL) return;
else{
if(n > 2 * u->num){
ans += u->count + 1;
countNum(u->r, n, ans);
}else{
countNum(u->l, n, ans);
}
}
}
int reversePairs(vector<int>& nums) {
node* root = NULL;
int ans = 0;
for(auto i = nums.rbegin(); i != nums.rend(); i++){
countNum(root, *i, ans);
Add(root, *i, 0);
}
return ans;
}
};
大意就是对每个倒序数先查询到底,计算出sum来,然后按照正常(小于就左子树,大于就右子树)插入(真的很麻烦,估计底下的树枝长的不得了,还不如二分暴力查找)
再就是merge&sort + 二分查找大法:
int countPairs(vector<int> &nums){
if(nums.size() <= 1) return 0;
int n = (int)nums.size();
int ans = 0;
vector<int> a(nums.begin(), nums.begin() + n/2);
vector<int> b(nums.begin() + n/2, nums.end());
ans += countPairs(a);
ans += countPairs(b);
int an = 0, bn = 0;
for(int i = 0; i<n; i++){
if(an != a.size() && (bn == b.size() || b[bn] >= a[an])){
long temp = ceil(1.0*a[an]/2);
int low = 0, high = (int)b.size();
while(low <= high){
int mid = (low + high) / 2;
if(b[mid] < temp) low = mid + 1;
else high = mid;
if(low == high) break;
}
ans += low;
nums[i] = a[an++];
}
else{
nums[i] = b[bn++];
}
}
return ans;
}
大意就是先分再和,合的时候(求逆序对和的时候直接比较完大小就可以sum+=bn了),但是这里就不能直接sum+=,需要用二分法找到真正的bn位置,然后sum+=bn。(暴力暴力)
最后就是树状数组了
493. Reverse Pairs
不负责任粘贴他人代码
public class Solution {
public int reversePairs(int[] nums) {
int res = 0;
int n = nums.length;
if(n == 0) return res;
// reflection
Map<Long, Integer> map = new HashMap();
long[] sorted = new long[2*n];
for(int i = 0; i < n; i++) {
sorted[2*i] = nums[i];
sorted[2*i + 1] = (long) nums[i] * 2;
}
Arrays.sort(sorted);
int idx = 1;
for(long num : sorted) {
if(!map.containsKey(num)) map.put(num, idx++);
}
BIT t = new BIT(idx);
int sum = 0;
for(int j = 0; j < n; j++) {
// find how many number > 2 * nums[j]
long num = (long) nums[j];
res += sum - t.sum(map.get(num*2));
t.add(map.get(num), 1);
sum++;
}
return res;
}
class BIT {
int n;
int[] tree;
BIT(int n) { this.n = n; tree = new int[n]; }
protected int sum(int i) {
int res = 0;
while(i > 0) {
res += tree[i];
i -= i & -i;
}
return res;
}
protected void add(int i, int val) {
while(i < n) {
tree[i] += val;
i += i & -i;
}
}
}
}
然后困扰了两天的题目就要继续困扰下去了。
参考:
Reverse Pairs (第二周:分治法)
【算法】逆序对问题的四种解法(归并排序,BST,树状数组,线段树)及变形