题目:
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.
leetcode链接
Example1:
Input: [1,3,2,3,1]
Output: 2
Example2:
Input: [2,4,3,5,1]
Output: 3
思路:
- 用二叉索引树方法(Binary Index Tree)(BIT),先将数组复制一份,然后排序,这样做之后我们可以得到具体索引所在位置的元素在整个数组中排序的位置。
- 一边逆序遍历原数组,一边更新索引树。因为是逆序遍历,假如当前遍历到索引为i = k(k <= n -1), 那么索引树已经有值的元素,一定是出现在k之后。所以如果我们能够找到小于nums[k]/2的数,则可以满足题目的条件 i < j and nums[i] > 2*nums[j]。
分析第一个例子:
n = 5, copy = [1, 1, 2, 3, 3]
i=4
时,num = nums[4] = 1
,尝试在BIT中找小于0.5的数的索引,得到结果为0(res = 0
);然后将当前的值的索引及其之后的父节点值加1。因为1在copy中首次出现的位置为0,也就是为所有元素中第一小的数,BIT中索引为0+ 1 = 1
以及之后的父节点都增加一,BIT为[0, 1, 1, 0, 1, 0]
。
i=3
时,num = nums[3] = 3
,尝试在BIT中找小于1.5的数的索引,得到索引值为2,在BIT中搜索索引值为2的节点以及其孩子节点的的值,得到值为1(res = 1
);然后将当前的值(3)的索引及其之后的父节点值加1。因为3在copy中首次出现的位置为3,BIT中索引为3+1=4
以及之后的父节点都增加一,BIT为[0, 1, 1, 0, 2, 0]
。
i=2
时,num = nums[3] = 2
,尝试在BIT中找小于1.0的数的索引,得到索引值为0,在BIT中搜索索引值为0的节点的值,得到值为0(res = 1
);然后将当前的值(2)的索引及其之后的父节点值加1。因为2在copy中首次出现的位置为2,BIT中索引为2+1 =3以及之后的父节点都增加一,BIT为
[0, 1, 1, 1, 3, 0]`。
i=1
时,num = nums[1] = 3
,尝试在BIT中找小于1.5的数的索引,得到索引值为2,在BIT中搜索索引值为2的节点以及其孩子节点的值,得到值为1(res = 2
);然后将当前的值(3)的索引及其之后的父节点值加1。因为3在copy中首次出现的位置为3,BIT中索引为3+1=4
以及之后的父节点都增加一,BIT为[0, 1, 1, 1, 4, 0]
。
i=0
时,num = nums[0] = 1
,尝试在BIT中找小于0.5的数的索引,得到结果为0(res = 2
);然后将当前的值的索引及其之后的父节点值加1。因为1在copy中首次出现的位置为0,也就是为所有元素中第一小的数,BIT中索引为0+ 1 = 1
以及之后的父节点都增加一,BIT为[0, 2, 2, 1, 5, 0]
。
C++代码:
class Solution {
public:
int reversePairs(vector<int>& nums) {
if(nums.empty()) return 0;
int n = nums.size();
vector<int> BIT(n+1, 0);
vector copy = nums;
sort(copy.begin(), copy.end());
int res = 0;
for(int i = n-1; i >= 0; i--){
int num = nums[i];
res += search(BIT, index(copy, 1.0*num/2));
insert(BIT, index(copy, num));
}
return res;
}
void insert(vector<int>& BIT, int i){
i += 1;
while(i < BIT.size()){
BIT[i]++;
i += (i&-i);
}
}
int search(vector<int>& BIT, int i){
int cnt = 0;
while(i > 0){
cnt += BIT[i];
i -= (i & -i);
}
return cnt;
}
int index(vector<int>& copy, double val){
int low = 0, high = copy.size();
while(low < high){
int mid = low + (high - low)/2;
if(copy[mid] >= val) {
high = mid;
}
else{
low = mid +1;
}
}
return low;
}
};