在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。
示例 1:
输入: [7,5,6,4]
输出: 5
限制:
0 <= 数组长度 <= 50000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shu-zu-zhong-de-ni-xu-dui-lcof
解法:
树状数组维护前缀和。树状数组的单点更新和查询的时间复杂度都是O(logn)。对于元素i,我们要求逆序对,就需要统计在该元素之前出现了多少个比元素i大的值。可以用树状数组动态维护前缀和。本题还需要先进行离散化以优化空间,离散化为将原数组元素映射到一个连续的区间。
class Solution {
//const int N = 1e5;
vector<int> C;
// 返回2^k, 其中k表示x从低位到高位连续0的个数(如8(1000)k=3;5(101)k=0;)
int lowbit(int x)
{
return x&(-x);
}
// 更新值
void update(int id, int num, int N)
{
while (id <= N)
{
C[id] += num;
id += lowbit(id); //不断加上最低位
}
return;
}
// 求和
int query(int id)
{
int ans = 0;
while (id)
{
ans += C[id];
id -= lowbit(id); //不断减去最低位
}
return ans;
}
public:
int reversePairs(vector<int>& nums) {
vector<int> tmp(nums.begin(), nums.end());
sort(tmp.begin(), tmp.end());
int len = nums.size();
for(int i = 0; i < len; ++i)
{
int id = lower_bound(tmp.begin(), tmp.end(), nums[i]) - tmp.begin();
nums[i] = len - id; //因为求逆序对,所以将元素值大的映射到小值去
}
C.resize(len+1);
int ans = 0;
for(int i = 0; i < len; ++i)
{
ans += query(nums[i] - 1);
update(nums[i], 1, len);
}
return ans;
}
};