剑指 Offer 51. 数组中的逆序对

本文介绍了一种利用树状数组求解数组中逆序对数量的方法。通过离散化和树状数组的前缀和特性,可以在O(n log n)的时间复杂度内解决此问题。示例给出了针对数组[7, 5, 6, 4]的解法,输出逆序对总数为5。
摘要由CSDN通过智能技术生成

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数。

示例 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;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值