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

76 阅读1分钟

收获

  • lower_bound的使用,lower_bound()是采用二分查找,时间复杂度为O(log(n))
要求nums数组是一个有序数组
lower_bound(nums.begin(),nums.end(),num)返回一个地址
lower_bound查找不小于目标值的第一个元素。
也就是说,使用该函数在指定范围内查找某个目标值时,
最终查找到的不一定是和目标值相等的元素,还可能是比目标值大的元素。


lower_bound(nums.begin(),nums.end(),num)-nums.begin()+1,返回相应下标,从1开始
  • 离散化树状数组
  • 巩固树状数组

难度:困难

题目描述

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

示例

输入: [7,5,6,4]
输出: 5

限制: 0 <= 数组长度 <= 50000

解题思路

  • 典型的树状数组题,且要采用离散化,动态维护前缀关系
  • 离散化思路:

(1)将数组内元素定位到排序后的下标

nums:[7,5,6,4]
排序后:[4,5,6,7]
nums对应下标:[4,2,3,1]
  • 剩下的就是树状数组模板题套用

相关解题代码

class Solution {
public:
    vector<int>tree;
    int n;
    int lowbit(int x){return x&(-x);}
    int querty(int x){
        int res=0;
        while(x){
            res+=tree[x];
            x-=lowbit(x);
        }
        return res;
    }
    void update(int x){
        while(x<=n){
            ++tree[x];
            x+=lowbit(x);
        }
    }
    int reversePairs(vector<int>& nums) {
        n=nums.size();tree.resize(n+1);
        /**
        离散化树状数组
        ***/
        vector<int>temp=nums;sort(temp.begin(),temp.end());
        for(int &num : nums){
            num=lower_bound(temp.begin(),temp.end(),num)-temp.begin()+1;
        }
        /**
        树状数组查询,更新
        **/
        int ans=0;
        for(int i=n-1;i>=0;i--){
            ans+=querty(nums[i]-1);
            update(nums[i]);
        }
        return ans;
    }
};